[
  {
    "path": ".gitignore",
    "content": "/target/\n/.idea/\n/*.iml\n"
  },
  {
    "path": "README.md",
    "content": "![swap](skorbut.png)\n\n## What is Skorbut?\n\nSkorbut is a simple teaching environment for a subset of C with a memory visualizer.\nIf you ever had trouble visualizing arrays and pointers, you have come to the right place.\n\n*Skorbut* is German for *scurvy*, an illness that is caused by a lack of Vitamin C.\nSkorbut also lacks C in the sense that it implements only a restricted subset of C.\n\n## Getting started\n\nPlease take the time to **read the following instructions carefully.**\nMost problems stem from skipping or misunderstanding important steps.\n\n### ☕ Windows & macOS\n\n1. Visit https://adoptium.net\n\n2. Click \"Latest release\" button to download Java installer\n\n3. Wait for download to finish\n\n4. Open the `Downloads` folder (via Windows Explorer or Finder/Spotlight, respectively) and double-click `OpenJDK...` to start Java installer\n\n5. Click Next, Next, Install, Finish\n\n6. Click [skorbut.jar](https://raw.githubusercontent.com/fredoverflow/skorbut/release/skorbut.jar) to download Skorbut<br>\n**If Skorbut fails to download**, continue with ⚠️ Troubleshooting *Windows*, or ⚠️ Troubleshooting *macOS*\n\n7. Open the `Downloads` folder and double-click `skorbut.jar` to start Skorbut<br>\n**If Skorbut fails to start**, continue with ⚠️ Troubleshooting *Windows*, or ⚠️ Troubleshooting *macOS*\n\n### ⚠️ Troubleshooting *Windows*\n\nSteps 1 through 5 (install Java) worked, but steps 6 (download Skorbut) or 7 (start Skorbut) failed? Then read on.\n\n- Move your mouse over the script below\n- A button appears in the top right corner of the script\n- Click that button to copy the script\n```cmd\ncd Downloads\nif exist skorbut.jar.zip erase skorbut.jar.zip\ncurl -o skorbut.jar https://raw.githubusercontent.com/fredoverflow/skorbut/release/skorbut.jar\necho java -version > skorbut.cmd\necho java -jar skorbut.jar >> skorbut.cmd\nskorbut.cmd\n\n```\n- Press the Windows key (the key on the bottom left with the Windows logo ⊞ on it)\n- Write `cmd` and confirm with Enter\n- A terminal appears\n- Right-click anywhere inside that terminal to paste and execute the script\n\nFrom now on, simply double-click `skorbut.cmd` in the `Downloads` folder to start Skorbut.<br>\nFeel free to move `skorbut.jar` and `skorbut.cmd` to the Desktop or any other folder you prefer.\n\n### ⚠️ Troubleshooting *macOS*\n\nSteps 1 through 5 (install Java) worked, but steps 6 (download Skorbut) or 7 (start Skorbut) failed? Then read on.\n\n- Move your mouse over the script below\n- A button appears in the top right corner of the script\n- Click that button to copy the script\n```sh\ncd Downloads\ncurl -o skorbut.jar https://raw.githubusercontent.com/fredoverflow/skorbut/release/skorbut.jar\nchmod +x skorbut.jar\necho java -version > skorbut.sh\necho java -jar skorbut.jar >> skorbut.sh\nchmod +x skorbut.sh\n./skorbut.sh\n\n```\n- Press `Command⌘ Space` (or click the magnifying glass 🔍 in the top right corner of the screen) to open Spotlight\n- Write `terminal` and confirm with Enter\n- A terminal appears\n- Press `Command⌘ V` to paste and execute the script\n\nFrom now on, simply double-click `skorbut.sh` in the `Downloads` folder to start Skorbut.<br>\nFeel free to move `skorbut.jar` and `skorbut.sh` to the Desktop or any other folder you prefer.\n\n### 🐧 Ubuntu, Linux Mint, Debian...\n\n```sh\nsudo apt install default-jdk\ncd Downloads\ncurl -o skorbut.jar https://raw.githubusercontent.com/fredoverflow/skorbut/release/skorbut.jar\nchmod +x skorbut.jar\necho java -version > skorbut.sh\necho java -jar -Dsun.java2d.opengl=True skorbut.jar >> skorbut.sh\nchmod +x skorbut.sh\n./skorbut.sh\n\n```\n\nFrom now on, simply double-click `skorbut.sh` in the `Downloads` folder to start Skorbut.<br>\nFeel free to move `skorbut.jar` and `skorbut.sh` to the Desktop or any other folder you prefer.\n\n### I would rather compile Skorbut from source!\n\n```\ngit clone https://github.com/fredoverflow/freditor\ncd freditor\nmvn install\ncd ..\ngit clone https://github.com/fredoverflow/skorbut\ncd skorbut\nmvn package\n```\n\nThe executable `skorbut.jar` will be located inside the `target` folder.\n\n## How do I save my code?\n\nThe code is automatically saved to a new file each time you click the start button.\nThe save folder is named `skorbut`, and it is located in your home directory.\nThe full path is displayed in the title bar.\n\n## Does Skorbut support auto-indentation?\n\nYes, just hit Enter or Tab.\n\n## What about auto-completion?\n\nCtrl+Space after an identifier auto-completes to the longest common prefix of all identifiers in scope.\nFor example, if `foo`, `bar` and `baz` are in scope, then `f` will be auto-completed to `foo`,\nbut `b` will only be auto-completed to `ba`, because both `bar` and `baz` start with `ba`.\n\nSkorbut has scope-aware auto-completion for all identifiers *except* `struct` members;\nthose are auto-completed globally, i.e. after `.` or `->`, *all* `struct` members are considered for auto-completion.\n(That's because auto-completion has no type information available yet. Changing this would be a Herculean task.)\n\n## What features of C are currently missing?\n\nNon-exhaustive list off the top of my head:\n\n| Feature             | Priority |\n| ------------------- | -------- |\n| preprocessor        | very low |\n| variadic functions  | very low |\n| compound assignment | low      |\n| null pointer        | medium   |\n| union               | very low |\n| return struct       | low      |\n\n## Wait, no preprocessor? How do I `#include <stdio.h>`?\n\nYou don't need to include anything, the following standard library functions are already available:\n\n- printf\n- scanf\n- puts\n- putchar\n- getchar\n- malloc\n- free\n- realloc\n- qsort\n- bsearch\n- strlen\n- strcmp\n- pow\n- time\n\n## What about my own header files?\n\nSkorbut does not support multiple translation units, so there would be no point in supporting header files.\n\n## How do I define constants without `#define`?\n\nFor integral constants, you can use anonymous enumerations like `enum { N = 10 };`\n\n## Keyboard shortcuts\n\n| Windows      | Effect                | Macintosh        |\n| -----------: | :-------------------: | ---------------- |\n| F1           | show type             | F1               |\n| F3           | declaration<br>usages | F3               |\n| F5           | step into             | F5               |\n| F6           | step over             | F6               |\n| F7           | step return           | F7               |\n| Tab<br>Enter | auto-indent           | Tab<br>Enter     |\n| Ctrl Space   | auto-complete         | Control (Shift) Space |\n| Ctrl Alt R   | rename symbol         | Command Option R |\n| Ctrl D       | delete line           | Command D        |\n| Ctrl C       | copy                  | Command C        |\n| Ctrl X       | cut                   | Command X        |\n| Ctrl V       | paste                 | Command V        |\n| Ctrl Z       | undo                  | Command Z        |\n| Ctrl Y       | redo                  | Command Y        |\n"
  },
  {
    "path": "pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>fredoverflow</groupId>\n    <artifactId>skorbut</artifactId>\n    <version>0.1.0-SNAPSHOT</version>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <kotlin.code.style>official</kotlin.code.style>\n        <kotlin.version>2.2.21</kotlin.version>\n        <kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <main.class>MainKt</main.class>\n        <java.runtime>${java.home}/lib/rt.jar</java.runtime>\n    </properties>\n\n    <profiles>\n        <profile>\n            <id>java-modules</id>\n            <activation>\n                <jdk>[9,)</jdk>\n            </activation>\n            <properties>\n                <java.runtime>${java.home}/jmods(!**.jar;!module-info.class)</java.runtime>\n            </properties>\n        </profile>\n    </profiles>\n\n    <dependencies>\n        <dependency>\n            <groupId>fredoverflow</groupId>\n            <artifactId>freditor</artifactId>\n            <version>0.1.0-SNAPSHOT</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.jetbrains.kotlin</groupId>\n            <artifactId>kotlin-stdlib</artifactId>\n            <version>${kotlin.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.junit.jupiter</groupId>\n            <artifactId>junit-jupiter-api</artifactId>\n            <version>5.14.0</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <sourceDirectory>src/main/kotlin</sourceDirectory>\n        <testSourceDirectory>src/test/kotlin</testSourceDirectory>\n\n        <plugins>\n            <plugin>\n                <groupId>org.jetbrains.kotlin</groupId>\n                <artifactId>kotlin-maven-plugin</artifactId>\n                <version>${kotlin.version}</version>\n                <executions>\n                    <execution>\n                        <id>compile</id>\n                        <goals>\n                            <goal>compile</goal>\n                        </goals>\n                    </execution>\n\n                    <execution>\n                        <id>test-compile</id>\n                        <goals>\n                            <goal>test-compile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n\n            <plugin>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>3.5.4</version>\n            </plugin>\n\n            <plugin>\n                <artifactId>maven-jar-plugin</artifactId>\n                <version>3.4.2</version>\n                <configuration>\n                    <archive>\n                        <manifest>\n                            <mainClass>${main.class}</mainClass>\n                        </manifest>\n                    </archive>\n                </configuration>\n            </plugin>\n\n            <plugin>\n                <groupId>com.github.wvengen</groupId>\n                <artifactId>proguard-maven-plugin</artifactId>\n                <version>2.6.1</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>proguard</goal>\n                        </goals>\n                    </execution>\n                </executions>\n                <configuration>\n                    <includeDependencyInjar>true</includeDependencyInjar>\n                    <outFilter>META-INF/MANIFEST.MF,!META-INF/**,!**.kotlin_*</outFilter>\n                    <outjar>${project.artifactId}.jar</outjar>\n                    <options>\n                        <!-- for some reason, the usual approach via configuration/libs/lib does not work -->\n                        <option>-libraryjars ${java.runtime}</option>\n                        <!-- preserve entry point, otherwise output jar would be empty -->\n                        <option>-keep public class ${main.class} { public static void main(java.lang.String[]); }</option>\n                        <!-- remove compiler-generated null checks for unneeded Java->Kotlin interoperability -->\n                        <option>-assumenosideeffects class kotlin.jvm.internal.Intrinsics { static void checkParameterIsNotNull(java.lang.Object, java.lang.String); }</option>\n                        <!-- hide annoying but harmless reflection warnings -->\n                        <option>-dontnote kotlin.**</option>\n                    </options>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "sloc",
    "content": "# sloc: count significant lines of code\n# INsignificant lines contain only spaces and/or braces\n\n# $1 directory\n# $2 extension\nfunction countInDirectory {\n\tlines=$(find \"src/$1\" -name \"*.$2\" -exec grep -vP \"^[{ }]*\\r?$\" {} + | wc -l)\n\tif [ $lines -gt 0 ]\n\tthen\n\t\tprintf \"$1: $lines\\n\"\n\tfi\n}\n\n# $1 language\n# $2 extension\nfunction countForLanguage {\n\tprintf \"$1\\n\"\n\tprintf \"==========\\n\"\n\tcountInDirectory main $2\n\tcountInDirectory test $2\n\tprintf \"\\n\"\n}\n\ncountForLanguage \"Kotlin\" \"kt\"\n"
  },
  {
    "path": "src/main/kotlin/Main.kt",
    "content": "import freditor.SwingConfig\nimport ui.MainFrame\nimport java.awt.EventQueue\n\nfun main() {\n    SwingConfig.metalWithDefaultFont(SwingConfig.SANS_SERIF_PLAIN_16)\n    EventQueue.invokeLater(::MainFrame)\n}\n"
  },
  {
    "path": "src/main/kotlin/common/Counter.kt",
    "content": "package common\n\nclass Counter {\n    private val counter = HashMap<Any, Int>()\n\n    fun count(x: Any): Int {\n        val soFar = counter.getOrElse(x) { 0 }\n        counter[x] = soFar + 1\n        return soFar\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/common/Diagnostic.kt",
    "content": "package common\n\ndata class Diagnostic(\n    val position: Int, override val message: String,\n    val secondPosition: Int = -1,\n    val columnDelta: Int = 0\n) : Exception(message) {\n\n    override fun toString(): String {\n        return if (secondPosition < 0) {\n            message\n        } else {\n            \"$message \\uD83D\\uDDB0 toggle position\"\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/common/Maps.kt",
    "content": "package common\n\nfun <K, V, M : MutableMap<K, V>> M.puts(keys: Array<out K>, value: V): M {\n    for (key in keys) {\n        put(key, value)\n    }\n    return this\n}\n\nfun <K, V, M : MutableMap<K, V>> M.puts(k1: K, k2: K, value: V): M {\n    put(k1, value)\n    put(k2, value)\n    return this\n}\n\nfun <K, V, M : MutableMap<K, V>> M.puts(k1: K, k2: K, k3: K, k4: K, value: V): M {\n    put(k1, value)\n    put(k2, value)\n    put(k3, value)\n    put(k4, value)\n    return this\n}\n\nfun <K, V, M : MutableMap<K, V>> M.puts(k1: K, k2: K, k3: K, k4: K, k5: K, k6: K, value: V): M {\n    put(k1, value)\n    put(k2, value)\n    put(k3, value)\n    put(k4, value)\n    put(k5, value)\n    put(k6, value)\n    return this\n}\n"
  },
  {
    "path": "src/main/kotlin/interpreter/BasicBlock.kt",
    "content": "package interpreter\n\nclass BasicBlock {\n    private val statements = ArrayList<FlatStatement>()\n    fun getStatements(): List<FlatStatement> = statements\n\n    fun isOpen(): Boolean {\n        return !isClosed()\n    }\n\n    fun isClosed(): Boolean {\n        return statements.lastOrNull() is TransferringControl\n    }\n\n    fun isEmpty(): Boolean {\n        return statements.isEmpty()\n    }\n\n    fun add(statement: FlatStatement) {\n        assert(isOpen())\n        statements.add(statement)\n    }\n\n    fun replaceSwitchPlaceholderWithRealSwitch(replacement: HashSwitch) {\n        assert(statements.last() === SwitchPlaceholder)\n        statements[statements.lastIndex] = replacement\n    }\n\n    var isReachable = false\n        private set\n\n    fun exploreReachability(resolve: (String) -> BasicBlock) {\n        if (!isReachable) {\n            isReachable = true\n            statements.lastOrNull()?.forEachSuccessor { label ->\n                resolve(label).exploreReachability(resolve)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/interpreter/BuildControlFlowGraph.kt",
    "content": "package interpreter\n\nimport semantic.types.ArithmeticType\nimport syntax.lexer.missingIdentifier\nimport syntax.tree.*\n\nval unusedEmptyHashMap = HashMap<ArithmeticValue, String>()\n\nclass State(\n    val continueTarget: String, val breakTarget: String,\n    val switchControlType: ArithmeticType?,\n    val cases: HashMap<ArithmeticValue, String>, var default: String?\n) {\n    constructor() : this(\"\", \"\", null, unusedEmptyHashMap, null)\n\n    fun openLoop(continueTarget: String, breakTarget: String): State {\n        return State(continueTarget, breakTarget, switchControlType, cases, default)\n    }\n\n    fun openSwitch(controlType: ArithmeticType, breakTarget: String): State {\n        return State(continueTarget, breakTarget, controlType, HashMap(), null)\n    }\n}\n\nclass BuildControlFlowGraph(function: FunctionDefinition) {\n    private val controlFlowGraph = LinkedHashMap<String, BasicBlock>()\n\n    private var lastGeneratedLabel = -1\n    private var currentLabelStr = \"\"\n    private var currentBasicBlock = BasicBlock()\n\n    private fun generateLabel(): String {\n        return \"${++lastGeneratedLabel}\"\n    }\n\n    private fun insertLabel(label: String) {\n        if (!currentBasicBlock.isEmpty()) {\n            jumpIfOpen(label)\n            currentBasicBlock = BasicBlock()\n        }\n        currentLabelStr = label\n        controlFlowGraph[currentLabelStr] = currentBasicBlock\n    }\n\n    private fun add(statement: FlatStatement) {\n        if (currentBasicBlock.isClosed()) {\n            currentBasicBlock = BasicBlock()\n            currentLabelStr = generateLabel()\n            controlFlowGraph[currentLabelStr] = currentBasicBlock\n        }\n        currentBasicBlock.add(statement)\n    }\n\n    private fun jumpIfOpen(target: String) {\n        if (currentBasicBlock.isOpen()) {\n            add(Jump(missingIdentifier, target))\n        }\n    }\n\n    init {\n        currentLabelStr = generateLabel()\n        insertLabel(currentLabelStr)\n\n        function.body.flatten(State())\n\n        val entry = controlFlowGraph.values.first()\n        entry.exploreReachability { controlFlowGraph[it]!! }\n        function.controlFlowGraph = controlFlowGraph\n    }\n\n    private fun List<Statement>.flatten(state: State) {\n        for (statement in this) {\n            statement.flatten(state)\n        }\n    }\n\n    private fun Statement.flatten(state: State) {\n        when (this) {\n            is Block -> {\n                statements.flatten(state)\n            }\n\n            is Declaration -> {\n                add(FlatDeclaration(specifiers, namedDeclarators))\n            }\n\n            is ExpressionStatement -> {\n                add(FlatExpressionStatement(expression))\n            }\n\n            is LabeledStatement -> {\n                insertLabel(label.text)\n                statement.flatten(state)\n            }\n\n            is Goto -> {\n                add(Jump(goto, label.text))\n            }\n\n            is IfThenElse -> {\n                if (e1se == null) {\n                    val execute = generateLabel()\n                    val done = generateLabel()\n\n                    add(JumpIf(condition, execute, done))\n\n                    insertLabel(execute)\n                    th3n.flatten(state)\n\n                    insertLabel(done)\n                } else {\n                    val executeThen = generateLabel()\n                    val executeElse = generateLabel()\n                    val done = generateLabel()\n\n                    add(JumpIf(condition, executeThen, executeElse))\n\n                    insertLabel(executeThen)\n                    th3n.flatten(state)\n                    jumpIfOpen(done)\n\n                    insertLabel(executeElse)\n                    e1se.flatten(state)\n\n                    insertLabel(done)\n                }\n            }\n\n            is Switch -> {\n                val done = generateLabel()\n\n                @Suppress(\"NAME_SHADOWING\")\n                val state = state.openSwitch(control.type.unqualified() as ArithmeticType, breakTarget = done)\n\n                add(SwitchPlaceholder)\n                val basicBlock = currentBasicBlock\n                body.flatten(state)\n                basicBlock.replaceSwitchPlaceholderWithRealSwitch(\n                    HashSwitch(control, state.cases, state.default ?: done)\n                )\n\n                insertLabel(done)\n            }\n\n            is Case -> {\n                if (state.switchControlType == null) {\n                    case.error(\"case label must be nested inside a switch\")\n                }\n                val caseLabel = generateLabel()\n                insertLabel(caseLabel)\n                val previous = state.cases.put(\n                    state.switchControlType.integralPromotions().cast(choice.value as ArithmeticValue),\n                    caseLabel\n                )\n                if (previous != null) {\n                    case.error(\"duplicate case label\")\n                }\n                body.flatten(state)\n            }\n\n            is Default -> {\n                if (state.switchControlType == null) {\n                    default.error(\"default label must be nested inside a switch\")\n                }\n                if (state.default != null) {\n                    default.error(\"duplicate default label\")\n                }\n                val defaultLabel = generateLabel()\n                insertLabel(defaultLabel)\n                state.default = defaultLabel\n                body.flatten(state)\n            }\n\n            is Do -> {\n                val bodyStart = generateLabel()\n                val checkCondition = generateLabel()\n                val done = generateLabel()\n\n                @Suppress(\"NAME_SHADOWING\")\n                val state = state.openLoop(continueTarget = checkCondition, breakTarget = done)\n\n                insertLabel(bodyStart)\n                body.flatten(state)\n\n                insertLabel(checkCondition)\n                add(JumpIf(condition, bodyStart, done))\n\n                insertLabel(done)\n            }\n\n            is While -> {\n                val checkCondition = generateLabel()\n                val bodyStart = generateLabel()\n                val done = generateLabel()\n\n                @Suppress(\"NAME_SHADOWING\")\n                val state = state.openLoop(continueTarget = checkCondition, breakTarget = done)\n\n                insertLabel(checkCondition)\n                add(JumpIf(condition, bodyStart, done))\n\n                insertLabel(bodyStart)\n                body.flatten(state)\n                add(ImplicitContinue(whi1e, checkCondition))\n\n                insertLabel(done)\n            }\n\n            is For -> {\n                when (init) {\n                    is ExpressionStatement -> {\n                        add(FlatExpressionStatement(init.expression))\n                    }\n\n                    is Declaration -> {\n                        add(FlatDeclaration(init.specifiers, init.namedDeclarators))\n                    }\n                }\n\n                val checkCondition = generateLabel()\n                val loopStart = generateLabel()\n                val updateCounter = generateLabel()\n                val done = generateLabel()\n\n                @Suppress(\"NAME_SHADOWING\")\n                val state = state.openLoop(continueTarget = updateCounter, breakTarget = done)\n\n                if (condition != null) {\n                    insertLabel(checkCondition)\n                    add(JumpIf(condition, loopStart, done))\n\n                    insertLabel(loopStart)\n                    body.flatten(state)\n\n                    insertLabel(updateCounter)\n                    if (update != null) {\n                        add(FlatExpressionStatement(update))\n                    }\n                    add(ImplicitContinue(f0r, checkCondition))\n\n                    insertLabel(done)\n                } else {\n                    insertLabel(loopStart)\n                    body.flatten(state)\n\n                    insertLabel(updateCounter)\n                    if (update != null) {\n                        add(FlatExpressionStatement(update))\n                    }\n                    add(ImplicitContinue(f0r, loopStart))\n\n                    insertLabel(done)\n                }\n            }\n\n            is Continue -> {\n                if (state.continueTarget.isEmpty()) {\n                    continu3.error(\"continue must be nested inside a loop\")\n                }\n                add(Jump(continu3, state.continueTarget))\n            }\n\n            is Break -> {\n                if (state.breakTarget.isEmpty()) {\n                    br3ak.error(\"break must be nested inside a loop or switch\")\n                }\n                add(Jump(br3ak, state.breakTarget))\n            }\n\n            is Return -> {\n                add(FlatReturn(r3turn, result))\n            }\n\n            is Assert -> {\n                add(FlatAssert(condition))\n            }\n\n            else -> {\n                error(\"no flatten for $this\")\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/interpreter/Console.kt",
    "content": "package interpreter\n\nimport semantic.types.DoubleType\nimport semantic.types.FloatType\nimport semantic.types.SignedCharType\nimport semantic.types.SignedIntType\nimport syntax.lexer.Token\nimport text.skipDigits\n\nimport java.util.concurrent.LinkedBlockingDeque\nimport java.util.concurrent.atomic.AtomicBoolean\n\nclass Console {\n    private val output = StringBuilder()\n\n    var isDirty: Boolean = false\n        private set\n\n    private var input = StringBuilder()\n\n    private val queue = LinkedBlockingDeque<Char>()\n    private val blocked = AtomicBoolean(false)\n\n    fun isBlocked(): Boolean = blocked.get()\n\n    var update: Function0<Unit>? = null\n\n    fun puts(str: PointerValue) {\n        print(stringStartingAt(str))\n        putchar('\\n')\n    }\n\n    fun putchar(x: Char) {\n        output.append(x)\n        isDirty = true\n    }\n\n    fun print(x: CharSequence) {\n        output.append(x)\n        isDirty = true\n    }\n\n    fun printf(format: Token, arguments: List<Value>): Int {\n        val sb = StringBuilder()\n        val args = arguments.iterator()\n        val fmt = format.text\n        var i = 0\n        var k = fmt.indexOf('%')\n        while (k != -1) {\n            sb.append(fmt, i, k)\n            if (fmt[++k] == '%') {\n                sb.append('%')\n            } else {\n                i = k\n                k = fmt.skipDigits(i) // width\n                if (fmt[k] == '.') {\n                    k = fmt.skipDigits(k + 1) // precision\n                }\n                val specifier = fmt.substring(i - 1, k + 1)\n                sb.append(formatValue(args.next(), specifier))\n            }\n            i = k + 1\n            k = fmt.indexOf('%', i)\n        }\n        sb.append(fmt, i, fmt.length)\n        print(sb)\n        return sb.length\n    }\n\n    private fun formatValue(value: Value, specifier: String): String {\n        return when (specifier.last()) {\n            'c' -> specifier.format((value as ArithmeticValue).value.toLong().toInt().and(0xff))\n\n            'i' -> specifier.replace('i', 'd').format((value as ArithmeticValue).value.toLong().toInt())\n\n            'u' -> specifier.replace('u', 'd').format((value as ArithmeticValue).value.toLong().and(0xffffffff))\n\n            'd', 'o', 'x', 'X' -> specifier.format((value as ArithmeticValue).value.toLong().toInt())\n\n            'e', 'E', 'f', 'g', 'G' -> specifier.format(java.util.Locale.ENGLISH, (value as ArithmeticValue).value)\n\n            's' -> specifier.format(stringStartingAt(value as PointerValue))\n\n            'p' -> specifier.replace('p', 's').format(value.show())\n\n            else -> error(\"illegal conversion specifier %${specifier.last()}\")\n        }\n    }\n\n    private fun stringStartingAt(start: PointerValue): CharSequence {\n        val sb = StringBuilder()\n        var ptr = start\n        var x = (ptr.referenced.evaluate() as ArithmeticValue).value\n        while (x != 0.0) {\n            sb.append(x.toInt().and(0xff).toChar())\n            ptr += 1\n            if (ptr.referenced.isSentinel()) error(\"missing NUL terminator\")\n            x = (ptr.referenced.evaluate() as ArithmeticValue).value\n        }\n        return sb\n    }\n\n    fun scanf(format: Token, arguments: List<Value>, after: Function0<Unit>?): Int {\n        val fmt = format.text\n        var i = 0\n        var a = 0\n        while (i < fmt.length) {\n            when (fmt[i++]) {\n                '\\t', '\\n', ' ' -> skipWhitespace()\n\n                '%' -> {\n                    val percent = i - 1\n                    if (i == fmt.length) format.stringErrorAt(percent, \"incomplete conversion specifier\")\n                    if (a == arguments.size) format.stringErrorAt(percent, \"missing argument after format string\")\n                    val arg = arguments[a++] as PointerValue\n                    val referenced = arg.referenced\n                    val type = referenced.type\n                    when (fmt[i++]) {\n                        'd' -> {\n                            if (type !== SignedIntType) format.stringErrorAt(percent, \"%d expects int*, not ${type.pointer()}\")\n                            skipWhitespace()\n                            val x = scanInt() ?: return a - 1\n                            referenced.assign(Value.signedInt(x))\n                        }\n\n                        'f' -> {\n                            if (type !== FloatType) format.stringErrorAt(percent, \"%f expects float*, not ${type.pointer()}\")\n                            skipWhitespace()\n                            val x = scanDouble() ?: return a - 1\n                            referenced.assign(Value.float(x.toFloat()))\n                        }\n\n                        'l' -> {\n                            if (i == fmt.length || fmt[i] != 'f') format.stringErrorAt(i, \"missing f after %l\")\n                            ++i\n                            if (type !== DoubleType) format.stringErrorAt(percent, \"%lf expects double*, not ${type.pointer()}\")\n                            skipWhitespace()\n                            val x = scanDouble() ?: return a - 1\n                            referenced.assign(Value.double(x))\n                        }\n\n                        'c' -> {\n                            if (type !== SignedCharType) format.stringErrorAt(percent, \"%c expects char*, not ${type.pointer()}\")\n                            referenced.assign(Value.signedChar(getchar()))\n                        }\n\n                        's' -> {\n                            if (type !== SignedCharType) format.stringErrorAt(percent, \"%s expects char*, not ${type.pointer()}\")\n                            val maxLen = referenced.bound - referenced.index - 1\n                            format.stringErrorAt(percent, \"%s is unsafe\\nuse %${maxLen}s instead\")\n                        }\n\n                        '1', '2', '3', '4', '5', '6', '7', '8', '9' -> {\n                            var len = fmt[i - 1] - '0'\n                            while (i < fmt.length && fmt[i] in '0'..'9') {\n                                len = len * 10 + (fmt[i++] - '0')\n                            }\n                            if (i == fmt.length || fmt[i] != 's') format.stringErrorAt(i, \"missing s after %$len\")\n                            ++i\n                            if (type !== SignedCharType) format.stringErrorAt(percent, \"%s expects char*, not ${type.pointer()}\")\n                            val maxLen = referenced.bound - referenced.index - 1\n                            if (len > maxLen) format.stringErrorAt(percent, \"%${len}s is ${len - maxLen} too long\\nuse %${maxLen}s instead\")\n                            skipWhitespace()\n                            val x = scanString(len)\n                            var obj = referenced\n                            for (c in x) {\n                                obj.assign(Value.signedChar(c))\n                                obj += 1\n                            }\n                            obj.assign(Value.NUL)\n                        }\n\n                        else -> format.stringErrorAt(percent, \"illegal conversion specifier %${fmt[i - 1]}\")\n                    }\n                    after?.invoke()\n                }\n\n                else -> if (getchar() != fmt[i - 1]) {\n                    unget()\n                    return a\n                }\n            }\n        }\n        return arguments.size\n    }\n\n    private fun skipWhitespace() {\n        @Suppress(\"ControlFlowWithEmptyBody\")\n        while (getchar().isWhitespace()) {\n        }\n        unget()\n    }\n\n    private fun scanInt(): Int? {\n        var c = getchar()\n        var sign = 1\n        if (c == '-') {\n            sign = -1\n            c = getchar()\n        }\n        if (c !in '0'..'9') return null\n        var x = c - '0'\n        while (getchar() in '0'..'9') {\n            x = x * 10 + (current - '0')\n        }\n        unget()\n        return sign * x\n    }\n\n    private fun scanDouble(): Double? {\n        var c = getchar()\n        var sign = 1\n        if (c == '-') {\n            sign = -1\n            c = getchar()\n        }\n        if (c !in '0'..'9') return null\n        var x = (c - '0').toDouble()\n        while (getchar() in '0'..'9') {\n            x = x * 10 + (current - '0')\n        }\n        if (current == '.') {\n            var decimal = 1.0\n            while (getchar() in '0'..'9') {\n                decimal /= 10\n                x += (current - '0') * decimal\n            }\n        }\n        unget()\n        return sign * x\n    }\n\n    private fun scanString(len: Int): CharSequence {\n        val sb = StringBuilder()\n        while (getchar() > ' ') {\n            sb.append(current)\n            if (sb.length == len) return sb\n        }\n        unget()\n        return sb\n    }\n\n    fun getText(): String {\n        isDirty = false\n        if (!isBlocked()) return output.toString()\n\n        val result = StringBuilder()\n        result.append(output)\n        result.append(input)\n        result.append('_')\n        return result.toString()\n    }\n\n    fun keyTyped(x: Char) {\n        when (x) {\n            in '\\u0020'..'\\u007e' -> input.append(x)\n            in '\\u00a0'..'\\u00ff' -> input.append(x)\n\n            '\\b' -> backspace()\n\n            '\\n' -> enter()\n\n            '\\u0004', '\\u001a' -> stop()\n        }\n    }\n\n    private fun backspace() {\n        val len = input.length\n        if (len > 0) {\n            input.setLength(len - 1)\n        }\n    }\n\n    private fun enter() {\n        input.append('\\n')\n        output.append(input)\n        val temp = input\n        input = StringBuilder()\n        blocked.set(false)\n        for (x in temp) {\n            queue.put(x)\n        }\n    }\n\n    fun stop() {\n        queue.put('\\uffff')\n    }\n\n    fun getchar(): Char {\n        val x: Char? = queue.poll()\n        if (x != null) return remember(x)\n\n        blocked.set(true)\n        update?.invoke()\n        val y: Char = queue.take()\n        return remember(y)\n    }\n\n    private fun remember(x: Char): Char {\n        current = x\n        return x\n    }\n\n    private var current = '\\u0000'\n\n    private fun unget() {\n        queue.putFirst(current)\n        current = '\\u0000'\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/interpreter/FlatStatements.kt",
    "content": "package interpreter\n\nimport syntax.lexer.Token\nimport syntax.lexer.missingIdentifier\nimport syntax.tree.DeclarationSpecifiers\nimport syntax.tree.Expression\nimport syntax.tree.NamedDeclarator\n\nsealed class FlatStatement {\n    abstract fun root(): Token\n\n    open fun forEachSuccessor(action: (String) -> Unit) {\n    }\n}\n\nsealed class TransferringControl : FlatStatement()\n\nclass Jump(val keyword: Token, val target: String) : TransferringControl() {\n    override fun root(): Token = keyword\n\n    override fun forEachSuccessor(action: (String) -> Unit) {\n        action(target)\n    }\n}\n\nclass ImplicitContinue(val keyword: Token, val target: String) : TransferringControl() {\n    override fun root(): Token = keyword\n\n    override fun forEachSuccessor(action: (String) -> Unit) {\n        action(target)\n    }\n}\n\nclass JumpIf(val condition: Expression, val th3n: String, val e1se: String) : TransferringControl() {\n    override fun root(): Token = condition.root()\n\n    override fun forEachSuccessor(action: (String) -> Unit) {\n        action(th3n)\n        action(e1se)\n    }\n}\n\nobject SwitchPlaceholder : TransferringControl() {\n    override fun root(): Token = missingIdentifier\n}\n\nclass HashSwitch(val control: Expression, val cases: HashMap<ArithmeticValue, String>, val default: String) :\n    TransferringControl() {\n    override fun root(): Token = control.root()\n\n    override fun forEachSuccessor(action: (String) -> Unit) {\n        cases.values.forEach { action(it) }\n        action(default)\n    }\n}\n\nclass FlatDeclaration(val specifiers: DeclarationSpecifiers, val namedDeclarators: List<NamedDeclarator>) :\n    FlatStatement() {\n    override fun root(): Token = specifiers.root()\n}\n\nclass FlatExpressionStatement(val expression: Expression) : FlatStatement() {\n    override fun root(): Token = expression.root()\n}\n\nclass FlatReturn(val r3turn: Token, val result: Expression?) : TransferringControl() {\n    override fun root(): Token = r3turn\n}\n\nclass FlatAssert(val condition: Expression) : FlatStatement() {\n    override fun root(): Token = condition.root()\n}\n"
  },
  {
    "path": "src/main/kotlin/interpreter/Interpreter.kt",
    "content": "package interpreter\n\nimport common.Diagnostic\nimport semantic.TypeChecker\nimport semantic.types.*\nimport syntax.lexer.Lexer\nimport syntax.lexer.Token\nimport syntax.lexer.TokenKind.*\nimport syntax.parser.Parser\nimport syntax.parser.translationUnit\nimport syntax.tree.*\nimport java.time.LocalTime\nimport java.time.format.DateTimeFormatter.ISO_TIME\nimport java.time.temporal.ChronoUnit.SECONDS\nimport kotlin.math.floor\nimport kotlin.math.pow\nimport kotlin.random.Random\n\nfun FunctionDefinition.returnType(): Type = (namedDeclarator.type as FunctionType).returnType\n\nclass Interpreter(program: String) {\n    val translationUnit = Parser(Lexer(program)).translationUnit()\n    val typeChecker = TypeChecker(translationUnit)\n\n    private val functions = translationUnit.functions.associateBy(FunctionDefinition::name)\n\n    var onMemorySet: Function1<Memory, Unit>? = null\n    private var memory = Memory(emptySet(), emptyList())\n        private set(value) {\n            field = value\n            onMemorySet?.invoke(value)\n        }\n\n    val console = Console()\n\n    var stackDepth = 0\n        private set\n    private var passedAssertions = 0\n\n    private var targetType: Type = VoidPointerType\n\n    init {\n        for (function in translationUnit.functions) {\n            BuildControlFlowGraph(function)\n        }\n    }\n\n    var before: Function1<Int, Unit>? = null\n    var after: Function0<Unit>? = null\n\n    fun run(cursor: Int, bottom: Int) {\n        val main = translationUnit.functions.firstOrNull { it.name() == \"main\" }\n        if (main != null) {\n            if (main.returnType() !== SignedIntType || main.parameters.isNotEmpty()) {\n                main.specifiers.root().error(\"int main() expected\")\n            }\n            runMain(main)\n        } else {\n            val (beforeCursor, afterCursor) = translationUnit.functions\n                .filter { it.returnType() === VoidType && it.parameters.isEmpty() }\n                .partition { it.closingBrace.end < cursor }\n\n            val entryPoint = afterCursor.firstOrNull() ?: beforeCursor.lastOrNull()\n            ?: throw Diagnostic(\n                bottom,\n                \"missing entry point, must provide one of:\\n· void allNamesAreFine()\\n· int  main()\"\n            )\n            run(entryPoint)\n        }\n    }\n\n    private fun runMain(main: FunctionDefinition) {\n        initializeMemory(main)\n        val exitCode = main.execute(emptyList()) as ArithmeticValue\n\n        console.print(\"\\nmain finished with exit code ${exitCode.value.toInt()}\\n\")\n        console.update?.invoke()\n\n        reportMemoryLeaks(main)\n    }\n\n    private fun run(entryPoint: FunctionDefinition) {\n        initializeMemory(entryPoint)\n        entryPoint.execute(emptyList())\n\n        if (passedAssertions != 0) {\n            val now = LocalTime.now().truncatedTo(SECONDS).format(ISO_TIME)\n            console.print(\"\\n[$now] ${entryPoint.name()}: ALL $passedAssertions assertions PASSED\\n\")\n            console.update?.invoke()\n        }\n        reportMemoryLeaks(entryPoint)\n    }\n\n    private fun initializeMemory(start: FunctionDefinition) {\n        val usedStringLiterals = HashSet<String>()\n\n        val exploredFunctions = hashSetOf(start)\n\n        val staticVariables: Map<String, NamedDeclarator> = translationUnit.declarations\n            .filter { declaration -> declaration.specifiers.storageClass != TYPEDEF }\n            .flatMap(Declaration::namedDeclarators)\n            .filter { namedDeclarator -> namedDeclarator.offset < 0 && namedDeclarator.type.requiresStorage() }\n            .associateBy { namedDeclarator -> namedDeclarator.name.text }\n        val usedStaticOffsets = HashSet<Int>()\n\n        fun explore(parent: Node) {\n            parent.walkChildren({}) { node ->\n                when (node) {\n                    is StringLiteral -> {\n                        usedStringLiterals.add(node.literal.text)\n                    }\n\n                    is Identifier -> {\n                        if (node.type is FunctionType) {\n                            functions[node.name.text]?.let { function ->\n                                if (exploredFunctions.add(function)) {\n                                    explore(function)\n                                }\n                            }\n                        } else if (node.symbol.offset < 0) {\n                            staticVariables[node.name.text]?.let { variable ->\n                                if (usedStaticOffsets.add(node.symbol.offset)) {\n                                    explore(variable)\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        explore(start)\n\n        val stringLiterals = typeChecker.stringLiterals\n        stringLiterals.retainAll(usedStringLiterals)\n\n        if (usedStaticOffsets.isEmpty()) {\n            memory = Memory(stringLiterals, emptyList())\n        } else {\n            memory = Memory(stringLiterals, staticVariables.values.map { namedDeclarator ->\n                if (namedDeclarator.offset in usedStaticOffsets) namedDeclarator else namedDeclarator.hidden()\n            })\n            for (namedDeclarator in staticVariables.values) {\n                with(namedDeclarator) {\n                    if (declarator is Declarator.Initialized && offset in usedStaticOffsets) {\n                        initialize(type, declarator.init, memory.staticVariables, offset + Int.MIN_VALUE)\n                    } else {\n                        defaultInitialize(type, memory.staticVariables, offset + Int.MIN_VALUE)\n                    }\n                }\n            }\n        }\n    }\n\n    private fun reportMemoryLeaks(function: FunctionDefinition) {\n        if (memory.heap.isNotEmpty()) {\n            function.closingBrace.error(\"${memory.heap.size} missing free calls\")\n        }\n    }\n\n    private fun FunctionDefinition.execute(arguments: List<Value>): Value {\n        ++stackDepth\n        try {\n            val stackFrame = Segment(stackFrameType)\n            memory.stack.add(stackFrame)\n            for ((param, arg) in parameters.zip(arguments)) {\n                param.type.cast(arg).store(stackFrame, param.offset)\n            }\n            after?.invoke()\n\n            var basicBlock = controlFlowGraph[\"0\"]!!.getStatements()\n            var pc = 0\n            while (pc != basicBlock.size) {\n                with(basicBlock[pc++]) {\n                    when (this) {\n                        is Jump -> {\n                            basicBlock = controlFlowGraph[target]!!.getStatements()\n                            pc = 0\n                        }\n\n                        is ImplicitContinue -> {\n                            basicBlock = controlFlowGraph[target]!!.getStatements()\n                            pc = 0\n                        }\n\n                        is JumpIf -> {\n                            val target = if (condition.delayedCondition()) th3n else e1se\n                            basicBlock = controlFlowGraph[target]!!.getStatements()\n                            pc = 0\n                        }\n\n                        is HashSwitch -> {\n                            val target = cases[(control.delayed() as ArithmeticValue).integralPromotions()] ?: default\n                            basicBlock = controlFlowGraph[target]!!.getStatements()\n                            pc = 0\n                        }\n\n                        is FlatDeclaration -> {\n                            for (namedDeclarator in namedDeclarators) {\n                                with(namedDeclarator) {\n                                    if (declarator is Declarator.Initialized && offset >= 0) {\n                                        before?.invoke(name.start)\n                                        initialize(type, declarator.init, stackFrame, offset)\n                                        after?.invoke()\n                                    }\n                                }\n                            }\n                        }\n\n                        is FlatExpressionStatement -> {\n                            expression.delayed()\n                        }\n\n                        is FlatReturn -> {\n                            if (result == null) {\n                                before?.invoke(r3turn.start)\n                                after?.invoke()\n                            } else {\n                                targetType = this@execute.returnType()\n                                return targetType.cast(result.delayed()).also { memory.popStackFrameUnlessEntryPoint() }\n                            }\n                        }\n\n                        is FlatAssert -> {\n                            if (condition is RelationalEquality && condition.right.type is ArithmeticType) {\n                                val left = condition.left.delayed()\n                                val right = condition.right.evaluate()\n                                if (relationalEquality(\n                                        left as ArithmeticValue,\n                                        condition.operator,\n                                        right as ArithmeticValue\n                                    ).isFalse()\n                                ) {\n                                    val leftShow = left.show()\n                                    condition.root().error(\n                                        \" $leftShow ${condition.operator} ${right.show()} \",\n                                        -leftShow.length - 2\n                                    )\n                                }\n                            } else if (!condition.delayedCondition()) {\n                                condition.root().error(\"assertion failed\")\n                            }\n                            ++passedAssertions\n                        }\n\n                        else -> error(\"no execute for $this\")\n                    }\n                }\n            }\n\n            before?.invoke(closingBrace.start)\n\n            if (returnType() !== VoidType) {\n                throw Diagnostic(closingBrace.start, \"missing return statement\")\n            }\n            memory.popStackFrameUnlessEntryPoint()\n            return VoidValue\n        } finally {\n            --stackDepth\n        }\n    }\n\n    private fun initialize(qualified: Type, init: Initializer, segment: Segment, start: Int): Int {\n        val type = qualified.unqualified()\n        when (init) {\n            is ExpressionInitializer -> {\n                return if (init.expression is StringLiteral && type is ArrayType && type.elementType == SignedCharType) {\n                    val str = init.expression.literal.text\n                    for ((i, c) in str.withIndex()) {\n                        segment[start + i] = Value.signedChar(c)\n                    }\n                    for (i in str.length until type.size) {\n                        segment[start + i] = Value.NUL\n                    }\n                    start + type.size\n                } else {\n                    targetType = type\n                    val value = type.cast(init.expression.evaluate())\n                    value.store(segment, start)\n                }\n            }\n\n            is InitializerList -> {\n                when (type) {\n                    is ArrayType -> return init.list.fold(start) { offset, initializer ->\n                        initialize(type.elementType, initializer, segment, offset)\n                    }\n\n                    is StructType -> return type.members.zip(init.list).fold(start) { offset, memberInitializer ->\n                        initialize(memberInitializer.first.type, memberInitializer.second, segment, offset)\n                    }\n                }\n            }\n        }\n        error(\"no init for $init\")\n    }\n\n    private fun defaultInitialize(qualified: Type, segment: Segment, start: Int): Int {\n        val type = qualified.unqualified()\n        when (type) {\n            is ArithmeticType -> {\n                segment[start] = type.defaultValue\n            }\n\n            is ArrayType -> {\n                (0 until type.size).fold(start) { offset, _ ->\n                    defaultInitialize(type.elementType, segment, offset)\n                }\n            }\n\n            is StructType -> {\n                type.members.fold(start) { offset, member ->\n                    defaultInitialize(member.type, segment, offset)\n                }\n            }\n        }\n        return start + type.count()\n    }\n\n    private fun Expression.delayed(): Value {\n        before?.invoke(root().start)\n        val result = evaluate()\n        after?.invoke()\n        return result\n    }\n\n    private fun Expression.delayedCondition(): Boolean {\n        return (delayed() as ArithmeticValue).isTrue()\n    }\n\n    private fun Expression.locate(): Object {\n        return when (this) {\n            is StringLiteral -> {\n                memory.stringObjects[literal.text]!!\n            }\n\n            is Identifier -> {\n                memory.makeObject(symbol)\n            }\n\n            is Subscript -> {\n                val left = left.evaluate()\n                val right = right.evaluate()\n                if (left is PointerValue && right is ArithmeticValue) {\n                    left.referenced.checkReferable() + right.value.toInt()\n                } else if (left is ArithmeticValue && right is PointerValue) {\n                    right.referenced.checkReferable() + left.value.toInt()\n                } else {\n                    error(\"no locate for $this\")\n                }\n            }\n\n            is DirectMemberAccess -> {\n                val struct = left.locate()\n\n                val type = struct.type.unqualified() as StructType\n                val member = type.member(right)\n                Object(struct.segment, struct.offset + member!!.offset, member.type, 0, 1)\n            }\n\n            is IndirectMemberAccess -> {\n                val pointer = left.evaluate() as PointerValue\n                val struct = pointer.referenced\n\n                val type = struct.type.unqualified() as StructType\n                val member = type.member(right)\n                Object(struct.segment, struct.offset + member!!.offset, member.type, 0, 1)\n            }\n\n            is Dereference -> {\n                val pointer = operand.evaluate() as PointerValue\n                pointer.referenced.checkReferable()\n            }\n\n            else -> error(\"no locate for $this\")\n        }\n    }\n\n    private fun Expression.evaluate(): Value {\n        value?.let { return it }\n        return when (this) {\n            is Identifier -> {\n                val symbolType = symbol.type\n                if (symbolType is FunctionType) {\n                    FunctionDesignator(symbol.name, symbolType)\n                } else {\n                    locate().evaluate()\n                }\n            }\n\n            is PrintfCall -> {\n                Value.signedInt(console.printf(format, arguments.map { it.evaluate() }))\n            }\n\n            is ScanfCall -> {\n                Value.signedInt(console.scanf(format, arguments.map { it.evaluate() }, after))\n            }\n\n            is Postfix -> {\n                val obj = operand.locate()\n                val oldValue = obj.evaluate()\n                val newValue = if (oldValue is ArithmeticValue) {\n                    val result = if (operator.kind == PLUS_PLUS) oldValue + Value.ONE else oldValue - Value.ONE\n                    oldValue.type.cast(result)\n                } else if (oldValue is PointerValue) {\n                    if (operator.kind == PLUS_PLUS) oldValue + 1 else oldValue - 1\n                } else {\n                    error(\"no evaluate for $this\")\n                }\n                obj.assign(newValue)\n                oldValue\n            }\n\n            is FunctionCall -> {\n                val func = (function.evaluate().decayed() as FunctionPointerValue).designator\n                val name = func.functionName\n                val definition = functions[name.text]\n                if (definition != null) {\n                    val evaluatedArguments = definition.parameters.zip(arguments).map {\n                        targetType = it.first.type\n                        it.second.evaluate()\n                    }\n                    return definition.execute(evaluatedArguments)\n                }\n                when (name.text) {\n                    \"pow\" -> {\n                        val base = (arguments[0].evaluate() as ArithmeticValue).value\n                        val exponent = (arguments[1].evaluate() as ArithmeticValue).value\n                        return ArithmeticValue(base.pow(exponent), DoubleType)\n                    }\n\n                    \"time\" -> {\n                        return ArithmeticValue(floor(System.currentTimeMillis() / 1000.0), UnsignedIntType)\n                    }\n\n                    \"puts\" -> {\n                        console.puts(arguments[0].evaluate() as PointerValue)\n                        return VoidValue\n                    }\n\n                    \"putchar\" -> {\n                        val arg = arguments[0].evaluate() as ArithmeticValue\n                        console.putchar(arg.value.toLong().toInt().and(0xff).toChar())\n                        return VoidValue\n                    }\n\n                    \"getchar\" -> {\n                        return Value.signedInt(console.getchar().code.toByte().toInt())\n                    }\n\n                    \"malloc\" -> {\n                        return allocate(function, arguments[0], memory::malloc, memory::malloc)\n                    }\n\n                    \"free\" -> {\n                        memory.free(arguments[0].evaluate() as PointerValue)\n                        return VoidValue\n                    }\n\n                    \"realloc\" -> {\n                        val pointer = arguments[0].evaluate() as PointerValue\n                        return allocate(\n                            function,\n                            arguments[1],\n                            // DO NOT REFACTOR: The lambdas call different realloc overloads!\n                            { type -> memory.realloc(pointer, type) },\n                            { type -> memory.realloc(pointer, type) }\n                        )\n                    }\n\n                    \"memswap\" -> {\n                        val p = arguments[0].evaluate() as PointerValue\n                        val q = arguments[1].evaluate() as PointerValue\n                        if (p.referenced.type != q.referenced.type) {\n                            error(\"${p.referenced.type} != ${q.referenced.type}\")\n                        }\n                        val size = (arguments[2].evaluate() as ArithmeticValue).value.toInt()\n                        val actualSize = p.referenced.type.sizeof()\n                        if (size != actualSize) {\n                            error(\"element type ${p.referenced.type} has size $actualSize, not $size\")\n                        }\n                        swap(p, q)\n                        return VoidValue\n                    }\n\n                    \"qsort\" -> {\n                        val base = arguments[0].evaluate() as PointerValue\n                        val count = (arguments[1].evaluate() as ArithmeticValue).value.toInt()\n                        val maxCount = base.referenced.bound - base.referenced.index\n                        if (count > maxCount) {\n                            error(\"There are only $maxCount elements in the array, not $count\")\n                        }\n                        val size = (arguments[2].evaluate() as ArithmeticValue).value.toInt()\n                        val actualSize = base.referenced.type.sizeof()\n                        if (size != actualSize) {\n                            error(\"element type ${base.referenced.type} has size $actualSize, not $size\")\n                        }\n                        val comp = arguments[3].evaluate().decayed() as FunctionPointerValue\n                        qsort(base, count, functions[comp.designator.functionName.text]!!)\n                        return VoidValue\n                    }\n\n                    \"bsearch\" -> {\n                        val key = arguments[0].evaluate() as PointerValue\n                        val base = arguments[1].evaluate() as PointerValue\n                        val count = (arguments[2].evaluate() as ArithmeticValue).value.toInt()\n                        val maxCount = base.referenced.bound - base.referenced.index\n                        if (count > maxCount) {\n                            error(\"There are only $maxCount elements in the array, not $count\")\n                        }\n                        val size = (arguments[3].evaluate() as ArithmeticValue).value.toInt()\n                        val actualSize = base.referenced.type.sizeof()\n                        if (size != actualSize) {\n                            error(\"element type ${base.referenced.type} has size $actualSize, not $size\")\n                        }\n                        val comp = arguments[4].evaluate().decayed() as FunctionPointerValue\n                        return bsearch(key, base, count, functions[comp.designator.functionName.text]!!)\n                    }\n\n                    \"strlen\" -> {\n                        val s = arguments[0].evaluate() as PointerValue\n                        return strlen(s, 0)\n                    }\n\n                    \"strcmp\" -> {\n                        val s = arguments[0].evaluate() as PointerValue\n                        val t = arguments[1].evaluate() as PointerValue\n                        return strcmp(s, t)\n                    }\n\n                    else -> error(\"undefined function $name\")\n                }\n            }\n\n            is Prefix -> {\n                val obj = operand.locate()\n                val oldValue = obj.evaluate()\n                val newValue = if (oldValue is ArithmeticValue) {\n                    val result = if (operator.kind == PLUS_PLUS) oldValue + Value.ONE else oldValue - Value.ONE\n                    oldValue.type.cast(result)\n                } else if (oldValue is PointerValue) {\n                    if (operator.kind == PLUS_PLUS) oldValue + 1 else oldValue - 1\n                } else {\n                    error(\"no evaluate for $this\")\n                }\n                obj.assign(newValue)\n                newValue\n            }\n\n            is Reference -> {\n                if (operand.type is FunctionType) {\n                    FunctionPointerValue(operand.evaluate() as FunctionDesignator)\n                } else {\n                    PointerValue(operand.locate())\n                }\n            }\n\n            is Dereference -> {\n                if ((operand.type.decayed() as PointerType).referencedType is FunctionType) {\n                    (operand.evaluate().decayed() as FunctionPointerValue).designator\n                } else {\n                    locate().evaluate()\n                }\n            }\n\n            is UnaryPlus -> {\n                unaryPlus(operand.evaluate())\n            }\n\n            is UnaryMinus -> {\n                unaryMinus(operand.evaluate())\n            }\n\n            is BitwiseNot -> {\n                bitwiseNot(operand.evaluate())\n            }\n\n            is LogicalNot -> {\n                logicalNot(operand.evaluate())\n            }\n\n            is Multiplicative -> {\n                multiplicative(left.evaluate(), operator, right.evaluate())\n            }\n\n            is Plus -> {\n                val left = left.evaluate()\n                val right = right.evaluate()\n                if (left is PointerValue && right is ArithmeticValue) {\n                    pointerPlus(left, this.left.type, right)\n                } else if (left is ArithmeticValue && right is PointerValue) {\n                    pointerPlus(right, this.right.type, left)\n                } else {\n                    plus(left, right)\n                }\n            }\n\n            is Minus -> {\n                val type = this.left.type\n                val left = left.evaluate()\n                val right = right.evaluate()\n                if (left is PointerValue && right is ArithmeticValue) {\n                    pointerMinus(left, type, right)\n                } else if (left is PointerValue && right is PointerValue) {\n                    if (type is VoidPointerType || type is ConstVoidPointerType) {\n                        Value.signedInt((left - right) * left.referenced.type.sizeof())\n                    } else {\n                        Value.signedInt(left - right)\n                    }\n                } else {\n                    minus(left, right)\n                }\n            }\n\n            is Shift -> {\n                shift(left.evaluate(), operator, right.evaluate(), type)\n            }\n\n            is RelationalEquality -> {\n                val left = left.evaluate()\n                val right = right.evaluate()\n                if (left is PointerValue && right is PointerValue) {\n                    Value.truth(\n                        when (operator.kind) {\n                            LESS -> left.less(right)\n                            MORE -> right.less(left)\n                            LESS_EQUAL -> !right.less(left)\n                            MORE_EQUAL -> !left.less(right)\n                            EQUAL_EQUAL -> left.equal(right)\n                            BANG_EQUAL -> !left.equal(right)\n\n                            else -> error(\"no evaluate for $this\")\n                        }\n                    )\n                } else {\n                    relationalEquality(left as ArithmeticValue, operator, right as ArithmeticValue)\n                }\n            }\n\n            is Bitwise -> {\n                bitwise(left.evaluate(), operator, right.evaluate(), type)\n            }\n\n            is Logical -> {\n                val left = left.evaluate() as ArithmeticValue\n                when (operator.kind) {\n                    AMPERSAND_AMPERSAND -> {\n                        if (left.isFalse()) Value.ZERO\n                        else (right.evaluate() as ArithmeticValue).normalizeBool()\n                    }\n\n                    BAR_BAR -> {\n                        if (left.isTrue()) Value.ONE\n                        else (right.evaluate() as ArithmeticValue).normalizeBool()\n                    }\n\n                    else -> error(\"no evaluate for $this\")\n                }\n            }\n\n            is Conditional -> {\n                val condition = condition.evaluate() as ArithmeticValue\n                val result = if (condition.isTrue()) th3n.delayed() else e1se.delayed()\n                type.cast(result)\n            }\n\n            is Cast -> {\n                type.cast(operand.evaluate())\n            }\n\n            is Assignment -> {\n                targetType = left.type\n                val value = left.type.cast(right.evaluate())\n                val obj = left.locate()\n                obj.preventSentinelAccess()\n                value.store(obj.segment, obj.offset)\n                value\n            }\n\n            is PlusAssignment -> {\n                val target = left.locate()\n                val left = target.evaluate()\n                val right = right.evaluate() as ArithmeticValue\n                val value = when (left) {\n                    is ArithmeticValue -> target.type.cast(left + right)\n\n                    is PointerValue -> pointerPlus(left, target.type, right)\n\n                    else -> error(\"no evaluate for $this\")\n                }\n                target.assign(value)\n                value\n            }\n\n            is MinusAssignment -> {\n                val target = left.locate()\n                val left = target.evaluate()\n                val right = right.evaluate() as ArithmeticValue\n                val value = when (left) {\n                    is ArithmeticValue -> target.type.cast(left - right)\n\n                    is PointerValue -> pointerMinus(left, target.type, right)\n\n                    else -> error(\"no evaluate for $this\")\n                }\n                target.assign(value)\n                value\n            }\n\n            is Comma -> {\n                left.evaluate()\n                right.evaluate()\n            }\n\n            else -> {\n                if (!isLocator) error(\"no evaluate for $this\")\n                locate().evaluate()\n            }\n        }\n    }\n\n    private fun Binary.pointerPlus(pointer: PointerValue, type: Type, arithmetic: ArithmeticValue): Value {\n        val delta = arithmetic.value.toInt()\n        return if (type is VoidPointerType || type is ConstVoidPointerType) {\n            val sizeof = pointer.referenced.type.sizeof()\n            if (delta % sizeof != 0) {\n                this.root().error(\"$delta is not a multiple of $sizeof\")\n            }\n            pointer + delta / sizeof\n        } else {\n            pointer + delta\n        }\n    }\n\n    private fun Binary.pointerMinus(pointer: PointerValue, type: Type, arithmetic: ArithmeticValue): Value {\n        val delta = arithmetic.value.toInt()\n        return if (type is VoidPointerType || type is ConstVoidPointerType) {\n            val sizeof = pointer.referenced.type.sizeof()\n            if (delta % sizeof != 0) {\n                this.root().error(\"$delta is not a multiple of $sizeof\")\n            }\n            pointer - delta / sizeof\n        } else {\n            pointer - delta\n        }\n    }\n\n    private fun qsort(base: PointerValue, count: Int, comp: FunctionDefinition) {\n        // Programming Pearls\n        // 11.3 Better Quicksorts\n        fun q(l: Int, u: Int) {\n            if (l < u) {\n                val pivot = base + l\n                swap(pivot, base + Random.nextInt(l, u + 1))\n                var i = l\n                var j = u + 1\n                while (true) {\n                    do ++i while (i <= u && (comp.execute(listOf(base + i, pivot)) as ArithmeticValue).value < 0)\n                    do --j while (/*     */ (comp.execute(listOf(base + j, pivot)) as ArithmeticValue).value > 0)\n                    if (i > j) break\n                    swap(base + i, base + j)\n                }\n                swap(pivot, base + j)\n                q(l, j - 1)\n                q(j + 1, u)\n            }\n        }\n        q(0, count - 1)\n    }\n\n    private fun swap(p: PointerValue, q: PointerValue) {\n        val a = p.referenced\n        val b = q.referenced\n        for (i in 0 until a.type.count()) {\n            val x = a.segment[a.offset + i]\n            val y = b.segment[b.offset + i]\n            a.segment[a.offset + i] = y\n            b.segment[b.offset + i] = x\n        }\n    }\n\n    private fun bsearch(key: PointerValue, base: PointerValue, count: Int, comp: FunctionDefinition): Value {\n        var left = 0\n        var right = count\n        while (left < right) {\n            val middle = (left + right).ushr(1)\n            val comparison = (comp.execute(listOf(key, base + middle)) as ArithmeticValue).value\n            when {\n                comparison < 0 -> right = middle\n\n                comparison > 0 -> left = middle + 1\n\n                else -> return base + middle\n            }\n        }\n        return base + count\n    }\n\n    private tailrec fun strlen(s: PointerValue, len: Int): ArithmeticValue {\n        val c = s.referenced.evaluate() as ArithmeticValue\n        return when {\n            (c == Value.NUL) -> Value.unsignedChar(len)\n\n            else -> strlen(s + 1, len + 1)\n        }\n    }\n\n    private tailrec fun strcmp(s: PointerValue, t: PointerValue): ArithmeticValue {\n        val c = s.referenced.evaluate() as ArithmeticValue\n        val d = t.referenced.evaluate() as ArithmeticValue\n        return when {\n            (c != d) -> (c - d)\n\n            (c == Value.NUL) -> Value.ZERO\n\n            else -> strcmp(s + 1, t + 1)\n        }\n    }\n\n    private fun allocate(\n        function: Expression,\n        size: Expression,\n        one: (Type) -> PointerValue,\n        many: (ArrayType) -> PointerValue\n    ): PointerValue {\n        if (targetType === VoidPointerType) {\n            function.root().error(\"cannot infer desired type to allocate via void*\")\n        }\n        val elementType = (targetType as PointerType).referencedType\n        val elementSize = elementType.sizeof()\n        val requestedBytes = (size.evaluate() as ArithmeticValue).value.toInt()\n        val arraySize = requestedBytes / elementSize\n        if (arraySize * elementSize != requestedBytes) {\n            size.root()\n                .error(\"$requestedBytes is not a multiple of $elementSize. Did you forget to multiply by sizeof(element type)?\")\n        }\n        return if (arraySize == 1) one(elementType)\n        else many(ArrayType(arraySize, elementType))\n    }\n}\n\nfun unaryPlus(x: Value): Value {\n    val a = x as ArithmeticValue\n    return Value.ZERO + a\n}\n\nfun unaryMinus(x: Value): Value {\n    val a = x as ArithmeticValue\n    return Value.ZERO - a\n}\n\nfun bitwiseNot(x: Value): Value {\n    val a = x as ArithmeticValue\n    return Value.MINUS_ONE - a\n}\n\nfun logicalNot(x: Value): Value {\n    val a = x as ArithmeticValue\n    return Value.truth(a.isFalse())\n}\n\nfun multiplicative(x: Value, operator: Token, y: Value): Value {\n    val a = x as ArithmeticValue\n    val b = y as ArithmeticValue\n    return when (operator.kind) {\n        ASTERISK -> a * b\n        SLASH -> a / b\n        PERCENT -> a % b\n\n        else -> error(\"no evaluate for $operator\")\n    }\n}\n\nfun plus(x: Value, y: Value): Value {\n    val a = x as ArithmeticValue\n    val b = y as ArithmeticValue\n    return a + b\n}\n\nfun minus(x: Value, y: Value): Value {\n    val a = x as ArithmeticValue\n    val b = y as ArithmeticValue\n    return a - b\n}\n\nfun shift(x: Value, operator: Token, y: Value, type: Type): Value {\n    val a = (x as ArithmeticValue).integralPromotions().value.toLong().toInt()\n    val b = (y as ArithmeticValue).integralPromotions().value.toLong().toInt()\n    val bits = when {\n        operator.kind == LESS_LESS -> log(a, \"<< \", b, a.shl(b))\n\n        x.type === UnsignedIntType -> log(a, \">>>\", b, a.ushr(b))\n\n        else -> log(a, \">> \", b, a.shr(b))\n    }\n    return type.cast(Value.signedInt(bits))\n}\n\nfun relationalEquality(x: ArithmeticValue, operator: Token, y: ArithmeticValue): ArithmeticValue {\n    val commonType = x.type.usualArithmeticConversions(y.type)\n    val a = commonType.cast(x).value\n    val b = commonType.cast(y).value\n    return Value.truth(\n        when (operator.kind) {\n            LESS -> a < b\n            MORE -> a > b\n            LESS_EQUAL -> a <= b\n            MORE_EQUAL -> a >= b\n            EQUAL_EQUAL -> a == b\n            BANG_EQUAL -> a != b\n\n            else -> error(\"no evaluate for $operator\")\n        }\n    )\n}\n\nfun bitwise(x: Value, operator: Token, y: Value, type: Type): Value {\n    val a = (x as ArithmeticValue).value.toLong().toInt()\n    val b = (y as ArithmeticValue).value.toLong().toInt()\n    val result = when (operator.kind) {\n        AMPERSAND -> log(a, \" & \", b, a.and(b))\n        CARET -> log(a, \" ^ \", b, a.xor(b))\n        BAR -> log(a, \" | \", b, a.or(b))\n\n        else -> error(\"no evaluate for $operator\")\n    }\n    return type.cast(Value.signedInt(result))\n}\n\nprivate fun log(x: Int, op: String, y: Int, z: Int): Int {\n    println(\"\"\"\n   ${x.toBinaryString32()} $x\n$op${y.toBinaryString32()} $y\n = ${z.toBinaryString32()} $z\"\"\")\n    return z\n}\n\nprivate fun Int.toBinaryString32(): String {\n    return nib(28) + nib(24) + \" \" + nib(20) + nib(16) + \" \" + nib(12) + nib(8) + \" \" + nib(4) + nib(0)\n}\n\nprivate fun Int.nib(pos: Int): String {\n    return NIBBLES[this.ushr(pos).and(15)]\n}\n\nprivate val NIBBLES = arrayOf(\n    \"0000\", \"0001\", \"0010\", \"0011\",\n    \"0100\", \"0101\", \"0110\", \"0111\",\n    \"1000\", \"1001\", \"1010\", \"1011\",\n    \"1100\", \"1101\", \"1110\", \"1111\",\n)\n"
  },
  {
    "path": "src/main/kotlin/interpreter/Memory.kt",
    "content": "package interpreter\n\nimport semantic.Symbol\nimport semantic.types.ArrayType\nimport semantic.types.SignedCharType\nimport semantic.types.StructType\nimport semantic.types.Type\nimport syntax.lexer.fakeIdentifier\nimport syntax.lexer.missingIdentifier\nimport syntax.tree.NamedDeclarator\nimport kotlin.math.min\n\nfun Iterable<String>.synthesizeStringConstantsType(): StructType {\n    val symbols = ArrayList<Symbol>()\n    val type = StructType(fakeIdentifier(\"string literals\"), symbols)\n    var offset = 0\n    for (str in this) {\n        val size = str.length + 1\n        symbols.add(Symbol(missingIdentifier, ArrayType(size, SignedCharType), offset))\n        offset += size\n    }\n    return type\n}\n\nfun Iterable<NamedDeclarator>.synthesizeStaticVariablesType(): StructType {\n    val symbols = ArrayList<Symbol>()\n    val type = StructType(fakeIdentifier(\"static variables\"), symbols)\n    for (namedDeclarator in this) {\n        with(namedDeclarator) {\n            symbols.add(Symbol(name, this.type, offset))\n        }\n    }\n    return type\n}\n\nclass Memory(stringLiterals: Iterable<String>, variables: Iterable<NamedDeclarator>) {\n    val stringObjects = HashMap<String, Object>()\n\n    val stringConstants = Segment(stringLiterals.synthesizeStringConstantsType())\n    val staticVariables = Segment(variables.synthesizeStaticVariablesType())\n    val stack = ArrayList<Segment>()\n    val heap = ArrayList<Segment>()\n\n    init {\n        var stringOffset = 0\n        for (stringLiteral in stringLiterals) {\n            stringObjects[stringLiteral] =\n                Object(stringConstants, stringOffset, ArrayType(stringLiteral.length + 1, SignedCharType), 0, 1)\n            for (x in stringLiteral) {\n                stringConstants[stringOffset++] = Value.signedChar(x)\n            }\n            stringConstants[stringOffset++] = Value.NUL\n        }\n        stringConstants.readOnlyErrorMessage = \"attempt to modify a string literal\"\n    }\n\n    fun makeObject(symbol: Symbol): Object {\n        return with(symbol) {\n            if (offset < 0) {\n                Object(staticVariables, offset + Int.MIN_VALUE, type, 0, 1)\n            } else {\n                Object(stack.last(), offset, type, 0, 1)\n            }\n        }\n    }\n\n    fun popStackFrameUnlessEntryPoint() {\n        if (stack.size > 1) {\n            stack.removeAt(stack.lastIndex).kill()\n        }\n    }\n\n    fun malloc(type: Type): PointerValue {\n        val segment = Segment(type)\n        heap.add(segment)\n        return PointerValue(Object(segment, 0, type, 0, 1))\n    }\n\n    fun malloc(arrayType: ArrayType): PointerValue {\n        val segment = Segment(arrayType)\n        heap.add(segment)\n        return PointerValue(Object(segment, 0, arrayType.elementType, 0, arrayType.size))\n    }\n\n    fun free(pointer: PointerValue) {\n        val obj = pointer.referenced\n        val segment = obj.segment\n\n        if (!segment.alive) throw AssertionError(\"dangling pointer\")\n        if (segment !in heap) throw AssertionError(\"free on non-heap segment\")\n        if (obj.offset != 0) throw AssertionError(\"free in the middle of segment\")\n\n        segment.kill()\n        heap.remove(segment)\n    }\n\n    fun realloc(pointer: PointerValue, type: Type): PointerValue {\n        val oldSegment = pointer.referenced.segment\n        val newSegment = Segment(type)\n        val smallerCount = min(oldSegment.count(), newSegment.count())\n        for (i in 0 until smallerCount) {\n            newSegment[i] = oldSegment[i]\n        }\n        free(pointer)\n        heap.add(newSegment)\n        return PointerValue(Object(newSegment, 0, type, 0, 1))\n    }\n\n    fun realloc(pointer: PointerValue, arrayType: ArrayType): PointerValue {\n        val oldSegment = pointer.referenced.segment\n        val newSegment = Segment(arrayType)\n        val smallerCount = min(oldSegment.count(), newSegment.count())\n        for (i in 0 until smallerCount) {\n            newSegment[i] = oldSegment[i]\n        }\n        free(pointer)\n        heap.add(newSegment)\n        return PointerValue(Object(newSegment, 0, arrayType.elementType, 0, arrayType.size))\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/interpreter/Segment.kt",
    "content": "package interpreter\n\nimport semantic.types.Type\n\nclass Segment(val type: Type) {\n    private val memory: MutableList<Value> = MutableList(type.count()) { IndeterminateValue }\n    var readOnlyErrorMessage: String? = null\n\n    var alive = true\n        private set\n\n    fun kill() {\n        assert(alive)\n        alive = false\n    }\n\n    fun checkAlive() {\n        if (!alive) throw AssertionError(\"dangling pointer\")\n    }\n\n    fun count(): Int {\n        return type.count()\n    }\n\n    operator fun get(offset: Int): Value {\n        checkAlive()\n        return memory[offset]\n    }\n\n    operator fun set(offset: Int, newValue: Value) {\n        checkAlive()\n        if (readOnlyErrorMessage != null) throw AssertionError(readOnlyErrorMessage)\n        val oldValue = memory[offset]\n        assert(oldValue === IndeterminateValue || oldValue.type() == newValue.type()) {\n            \"$oldValue === $IndeterminateValue || ${oldValue.type()} == ${newValue.type()}\"\n        }\n        memory[offset] = newValue\n    }\n\n    operator fun set(obj: Object, newValue: Value) {\n        set(obj.offset, newValue)\n    }\n\n    fun replace(offset: Int, count: Int, source: Segment, sourceOffset: Int) {\n        checkAlive()\n        if (readOnlyErrorMessage != null) throw AssertionError(readOnlyErrorMessage)\n        source.checkAlive()\n\n        val sourceMemory = source.memory\n        for (i in 0 until count) {\n            memory[offset + i] = sourceMemory[sourceOffset + i]\n        }\n    }\n\n    companion object {\n        private var state = System.currentTimeMillis().toInt()\n\n        // generates 4,294,967,296 unique addresses before repeating\n        fun randomAddress(): Int {\n            state = state * 214013 + 2531011\n            return state\n        }\n    }\n\n    val address = randomAddress()\n}\n"
  },
  {
    "path": "src/main/kotlin/interpreter/Value.kt",
    "content": "package interpreter\n\nimport semantic.types.*\nimport syntax.lexer.Token\n\ndata class Object(val segment: Segment, val offset: Int, val type: Type, val index: Int, val bound: Int) {\n    init {\n        if (index < 0) throw AssertionError(\"negative index $index\")\n        if (index > bound) throw AssertionError(\"index $index out of bounds $bound\")\n    }\n\n    fun address(): Int {\n        val hi = segment.address\n        val lo = segment.type.sizeof(offset)\n        return hi.shl(16) + lo\n    }\n\n    fun isSentinel(): Boolean = (index == bound)\n\n    operator fun plus(delta: Int): Object = copy(offset = offset + delta * type.count(), index = index + delta)\n\n    operator fun minus(delta: Int): Object = copy(offset = offset - delta * type.count(), index = index - delta)\n\n    fun preventSentinelAccess() {\n        if (isSentinel()) throw AssertionError(\"index $index out of bounds $bound\")\n    }\n\n    fun checkReferable(): Object {\n        segment.checkAlive()\n        return this\n    }\n\n    fun isReferable(): Boolean {\n        return segment.alive\n    }\n\n    fun evaluate(): Value {\n        return when (val type = this.type.unqualified()) {\n            is ArrayType -> {\n                // array-to-pointer decay\n                PointerValue(copy(type = type.elementType, index = 0, bound = type.size))\n            }\n\n            is StructType -> {\n                // structs are not values, they must be preserved as objects\n                StructPseudoValue(this)\n            }\n\n            else -> {\n                preventSentinelAccess()\n                val result = segment[offset]\n                if (result == IndeterminateValue) throw AssertionError(\"read from uninitialized variable\")\n                result\n            }\n        }\n    }\n\n    fun assign(newValue: Value) {\n        preventSentinelAccess()\n        segment[this] = newValue\n    }\n}\n\ninterface Value {\n    fun type(): Type\n\n    fun show(): String\n\n    fun decayed(): Value = this\n\n    fun store(segment: Segment, offset: Int): Int {\n        segment[offset] = this\n        return offset + 1\n    }\n\n    companion object {\n        fun signedChar(x: Char): ArithmeticValue = ArithmeticValue(x.code.toByte().toDouble(), SignedCharType)\n        fun unsignedChar(x: Int): ArithmeticValue = ArithmeticValue(x.toDouble(), UnsignedCharType)\n\n        fun signedShort(x: Int): ArithmeticValue = ArithmeticValue(x.toDouble(), SignedShortType)\n        fun unsignedShort(x: Int): ArithmeticValue = ArithmeticValue(x.toDouble(), UnsignedShortType)\n\n        fun signedInt(x: Int): ArithmeticValue = ArithmeticValue(x.toDouble(), SignedIntType)\n        fun unsignedInt(x: Int): ArithmeticValue =\n            ArithmeticValue(x.toLong().and(0xffffffff).toDouble(), UnsignedIntType)\n\n        fun float(x: Float): ArithmeticValue = ArithmeticValue(x.toDouble(), FloatType)\n        fun double(x: Double): ArithmeticValue = ArithmeticValue(x, DoubleType)\n\n        val ONE = signedInt(1)\n        val NUL = signedChar('\\u0000')\n        val ZERO = signedInt(0)\n        val MINUS_ONE = signedInt(-1)\n\n        fun truth(x: Boolean): ArithmeticValue = if (x) ONE else ZERO\n    }\n}\n\nobject VoidValue : Value {\n    override fun type(): Type = VoidType\n\n    override fun show(): String = \"void\"\n}\n\ndata class ArithmeticValue(val value: Double, val type: ArithmeticType) : Value {\n    override fun type(): Type = type\n\n    override fun show(): String = type.show(value)\n\n    operator fun plus(that: ArithmeticValue): ArithmeticValue =\n        ArithmeticValue(value + that.value, type.usualArithmeticConversions(that.type)).trim()\n\n    operator fun minus(that: ArithmeticValue): ArithmeticValue =\n        ArithmeticValue(value - that.value, type.usualArithmeticConversions(that.type)).trim()\n\n    operator fun times(that: ArithmeticValue): ArithmeticValue =\n        ArithmeticValue(value * that.value, type.usualArithmeticConversions(that.type)).trim()\n\n    operator fun div(that: ArithmeticValue): ArithmeticValue =\n        ArithmeticValue(value / that.value, type.usualArithmeticConversions(that.type)).trim()\n\n    operator fun rem(that: ArithmeticValue): ArithmeticValue =\n        ArithmeticValue(value % that.value, type.usualArithmeticConversions(that.type)).trim()\n\n    private fun trim(): ArithmeticValue = ArithmeticValue(type.trim(value), type)\n\n    fun integralPromotions(): ArithmeticValue = type.integralPromotions().cast(this)\n\n    fun isFalse(): Boolean = (value == 0.0)\n\n    fun isTrue(): Boolean = (value != 0.0)\n\n    fun normalizeBool(): ArithmeticValue = if (value == 0.0 || value == 1.0) this else Value.ONE\n}\n\ndata class PointerValue(val referenced: Object) : Value {\n    override fun type(): Type = PointerType(referenced.type)\n\n    override fun show(): String = \"%08x\".format(referenced.address())\n\n    operator fun plus(delta: Int): PointerValue = PointerValue(referenced.checkReferable() + delta)\n\n    operator fun minus(delta: Int): PointerValue = PointerValue(referenced.checkReferable() - delta)\n\n    operator fun minus(base: PointerValue): Int {\n        if (referenced.segment != base.referenced.segment) throw AssertionError(\"subtract across segments\")\n        return (referenced.offset - base.referenced.offset) / referenced.type.count()\n    }\n\n    infix fun equal(that: PointerValue): Boolean {\n        return this.referenced.segment === that.referenced.segment &&\n                this.referenced.offset == that.referenced.offset\n    }\n\n    infix fun less(that: PointerValue): Boolean {\n        if (this.referenced.segment !== that.referenced.segment) throw AssertionError(\"compare across segments\")\n        return this.referenced.offset < that.referenced.offset\n    }\n}\n\ndata class FunctionDesignator(val functionName: Token, val functionType: FunctionType) : Value {\n    override fun type(): Type = functionType\n\n    override fun show(): String = error(\"show on function designator\")\n\n    override fun decayed(): Value = FunctionPointerValue(this)\n}\n\ndata class FunctionPointerValue(val designator: FunctionDesignator) : Value {\n    override fun type(): Type = PointerType(designator.functionType)\n\n    override fun show(): String = \"&${designator.functionName}\"\n}\n\nobject IndeterminateValue : Value {\n    override fun type(): Type = throw AssertionError(\"indeterminate value has no type\")\n\n    override fun show(): String = \"\"\n}\n\ndata class StructPseudoValue(val struct: Object) : Value {\n    override fun type(): Type = struct.type\n\n    override fun show(): String = \"SPV\"\n\n    override fun store(segment: Segment, offset: Int): Int {\n        val count = struct.type.count()\n        segment.replace(offset, count, struct.segment, struct.offset)\n        return offset + count\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/semantic/Linter.kt",
    "content": "package semantic\n\nimport interpreter.ArithmeticValue\nimport interpreter.BasicBlock\nimport interpreter.ImplicitContinue\nimport interpreter.returnType\nimport semantic.types.FunctionType\nimport semantic.types.VoidType\nimport semantic.types.isString\nimport syntax.lexer.Token\nimport syntax.lexer.TokenKind.*\nimport syntax.tree.*\n\nclass Linter(val translationUnit: TranslationUnit) : LinterBase() {\n    init {\n        detectLowHangingFruit()\n        detectUnusedVariables()\n        detectMissingReturns()\n        detectUnreachableCode()\n    }\n\n    private fun detectLowHangingFruit() {\n        translationUnit.walk({}) {\n            when (it) {\n                is Comma -> {\n                    it.left.detectOperatorWithoutEffect()\n                }\n\n                is ExpressionStatement -> {\n                    if (it.expression is FunctionCall) {\n                        if (it.expression.type !== VoidType) {\n                            it.expression.warn(\"ignored function result\")\n                        }\n                    } else {\n                        it.expression.detectOperatorWithoutEffect()\n                    }\n                }\n\n                is IfThenElse -> {\n                    it.condition.detectSuspiciousCondition()\n                }\n\n                is While -> {\n                    it.condition.detectSuspiciousCondition()\n                }\n\n                is Do -> {\n                    it.condition.detectSuspiciousCondition()\n                }\n\n                is For -> {\n                    it.condition?.detectSuspiciousCondition()\n                    it.update?.detectOperatorWithoutEffect()\n                }\n\n                is Assert -> {\n                    it.condition.detectSuspiciousCondition()\n                }\n            }\n        }\n    }\n\n    private fun Expression.detectOperatorWithoutEffect() {\n        val root = root()\n        when (root.kind) {\n            EQUAL_EQUAL -> {\n                root.warn(\"== is comparison, did you mean = instead?\")\n            }\n\n            IDENTIFIER -> when (type) {\n                is FunctionType -> root.warn(\"missing () for function call\")\n\n                else -> root.warn(\"$root has no effect\")\n            }\n\n            PLUS, HYPHEN -> when (this) {\n                is Binary -> root.warn(\"$root has no effect, did you mean $root= instead?\")\n\n                else -> root.warn(\"$root has no effect\")\n            }\n\n            OPENING_PAREN, SIZEOF, OPENING_BRACKET, DOT, HYPHEN_MORE,\n            AMPERSAND, ASTERISK, TILDE, BANG, SLASH, PERCENT,\n            LESS_LESS, MORE_MORE, LESS, MORE, LESS_EQUAL, MORE_EQUAL, BANG_EQUAL,\n            CARET, BAR, AMPERSAND_AMPERSAND, BAR_BAR,\n            DOUBLE_CONSTANT, FLOAT_CONSTANT, INTEGER_CONSTANT,\n            CHARACTER_CONSTANT, STRING_LITERAL -> {\n                root.warn(\"$root has no effect\")\n            }\n\n            else -> {\n            }\n        }\n    }\n\n    private fun Expression.detectSuspiciousCondition() {\n        when (this) {\n            is Assignment -> {\n                warn(\"= is assignment, did you mean == instead?\")\n            }\n\n            is RelationalEquality -> {\n                when {\n                    left is RelationalEquality -> {\n                        val op1 = left.operator\n                        val op2 = this.operator\n                        warn(\"a${op1}b${op2}c does not do what you think it does. You probably want a${op1}b && b${op2}c instead.\")\n                    }\n\n                    left.type.isString() || right.type.isString() -> {\n                        warn(\"a $operator b compares string addresses. To compare characters: strcmp(a, b) $operator 0\")\n                    }\n\n                    operator.kind == LESS || operator.kind == BANG_EQUAL -> {\n                        if (right is FunctionCall && right.function is Identifier && right.function.name.text == \"strlen\") {\n                            warn(\"consider replacing SLOW i${operator.kind}strlen(s) with FAST s[i]\")\n                        }\n                    }\n                }\n            }\n\n            is Logical -> {\n                left.detectSuspiciousCondition()\n                right.detectSuspiciousCondition()\n            }\n        }\n        val x = value\n        if (x is ArithmeticValue && this !is Constant) {\n            warn(\"condition is always ${x.isTrue()}\")\n        }\n    }\n\n    private fun detectUnusedVariables() {\n        val unusedVariables = HashSet<Token>()\n        translationUnit.walk({ node ->\n            when (node) {\n                is FunctionDefinition -> {\n                    node.parameters.forEach { unusedVariables.add(it.name) }\n                }\n\n                is Declaration -> {\n                    if (node.specifiers.storageClass != TYPEDEF) {\n                        for (namedDeclarator in node.namedDeclarators) {\n                            unusedVariables.add(namedDeclarator.name)\n                            if (namedDeclarator.declarator is Declarator.Initialized) {\n                                namedDeclarator.declarator.init.walk({}) {\n                                    when (it) {\n                                        is Identifier -> {\n                                            unusedVariables.remove(it.symbol.name)\n                                        }\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }) { node ->\n            when (node) {\n                is Identifier -> {\n                    unusedVariables.remove(node.symbol.name)\n                }\n            }\n        }\n        unusedVariables.forEach {\n            it.warn(\"unused variable $it\")\n        }\n    }\n\n    private fun detectMissingReturns() {\n        translationUnit.functions.forEach { it.detectMissingReturn() }\n    }\n\n    private fun FunctionDefinition.detectMissingReturn() {\n        if (returnType() !== VoidType) {\n            val exit = controlFlowGraph.values.last()\n            if (exit.isReachable && exit.isOpen()) {\n                root().warn(\"function ${name()} does not return a result on all code paths\")\n            }\n        }\n    }\n\n    private fun detectUnreachableCode() {\n        translationUnit.functions.forEach { it.detectUnreachableCode() }\n    }\n\n    private fun FunctionDefinition.detectUnreachableCode() {\n        controlFlowGraph.values.asSequence()\n            .filterNot(BasicBlock::isReachable)\n            .flatMap(BasicBlock::getStatements)\n            .filterNot { it.root().start < 0 }\n            .firstOrNull()\n            ?.apply {\n                if (this is ImplicitContinue) {\n                    root().warn(\"loop never repeats\")\n                } else {\n                    root().warn(\"unreachable code\")\n                }\n            }\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/semantic/LinterBase.kt",
    "content": "package semantic\n\nimport common.Diagnostic\nimport syntax.lexer.Token\nimport syntax.tree.Expression\n\nabstract class LinterBase {\n    private val warnings = ArrayList<Diagnostic>()\n\n    fun getWarnings(): List<Diagnostic> = warnings.sortedBy { it.position }\n\n    protected fun Token.warn(message: String) {\n        warnings.add(Diagnostic(start, message))\n    }\n\n    protected fun Expression.warn(message: String) {\n        root().warn(message)\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/semantic/SymbolTable.kt",
    "content": "package semantic\n\nimport semantic.types.FunctionType\nimport semantic.types.Type\nimport syntax.lexer.Token\nimport syntax.tree.Identifier\n\ndata class Symbol(val name: Token, val type: Type, val offset: Int) {\n    val usages = ArrayList<Identifier>()\n\n    override fun toString(): String = name.text\n}\n\nclass SymbolTable {\n    private val scopes = Array<HashMap<String, Symbol>>(128) { HashMap() }\n    private var current = 0\n    private val closedScopes = ArrayList<Map<String, Symbol>>()\n    private val allSymbols = ArrayList<Symbol>()\n\n    fun atGlobalScope(): Boolean {\n        return current == 0\n    }\n\n    fun openScope() {\n        scopes[++current] = HashMap()\n    }\n\n    fun closeScope() {\n        assert(!atGlobalScope()) { \"Attempt to close the global scope\" }\n        if (current == 1) {\n            closedScopes.clear()\n        } else {\n            closedScopes.add(scopes[current])\n        }\n        --current\n    }\n\n    fun reopenScope() {\n        ++current\n    }\n\n    inline fun <T> scoped(action: () -> T): T {\n        openScope()\n        val result = action()\n        closeScope()\n        return result\n    }\n\n    inline fun <T> rescoped(action: () -> T): T {\n        reopenScope()\n        val result = action()\n        closeScope()\n        return result\n    }\n\n    fun lookup(name: Token): Symbol? {\n        val text = name.text\n        for (i in current downTo 0) {\n            scopes[i][text]?.let { symbol -> return symbol }\n        }\n        return null\n    }\n\n    fun lookupInClosedScopes(name: Token): Symbol? {\n        val text = name.text\n        for (i in closedScopes.lastIndex downTo 0) {\n            closedScopes[i][text]?.let { symbol -> return symbol }\n        }\n        return null\n    }\n\n    fun declare(name: Token, type: Type, offset: Int): Symbol {\n        return declareIn(scopes[current], name, type, offset)\n    }\n\n    fun declareOutside(name: Token, type: Type, offset: Int): Symbol {\n        return declareIn(scopes[current - 1], name, type, offset)\n    }\n\n    private fun declareIn(scope: HashMap<String, Symbol>, name: Token, type: Type, offset: Int): Symbol {\n        val text = name.text\n        val previous = scope[text]\n        if (previous != null) {\n            if (previous.type is FunctionType && !previous.type.defined && type is FunctionType && type.defined) {\n                if (previous.type == type) {\n                    previous.type.defined = true\n                    previous.usages.add(Identifier(name).also { it.symbol = previous })\n                    return previous\n                } else {\n                    name.error(\"function definition signature does not agree with function declaration signature\")\n                }\n            } else {\n                name.error(\"symbol $name already declared in current scope\", previous.name)\n            }\n        } else {\n            val symbol = Symbol(name, type, offset)\n            scope[text] = symbol\n            allSymbols.add(symbol)\n            return symbol\n        }\n    }\n\n    fun currentFunction(): Symbol? {\n        return scopes[0].values.maxByOrNull { symbol -> symbol.name.start }\n    }\n\n    fun names(): Sequence<String> = sequence {\n        for (i in current downTo 0) {\n            for ((_, symbol) in scopes[i]) {\n                yield(symbol.name.text)\n            }\n        }\n    }\n\n    fun symbolAt(position: Int): Symbol? {\n        for (symbol in allSymbols) {\n            if (symbol.name.start <= position && position <= symbol.name.end) return symbol\n            for (usage in symbol.usages) {\n                if (usage.name.start <= position && position <= usage.name.end) return symbol\n            }\n        }\n        return null\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/semantic/TypeChecker.kt",
    "content": "package semantic\n\nimport common.Diagnostic\nimport freditor.Levenshtein\nimport interpreter.*\nimport semantic.types.*\nimport syntax.lexer.Token\nimport syntax.lexer.TokenKind.*\nimport syntax.lexer.fakeIdentifier\nimport syntax.lexer.missingIdentifier\nimport syntax.tree.*\nimport text.skipDigits\n\nclass TypeChecker(translationUnit: TranslationUnit) {\n    private val functionTokens: Map<String, Token> =\n        translationUnit.functions.map { it.namedDeclarator.name }.associateBy(Token::text)\n\n    private val symbolTable = SymbolTable()\n    val stringLiterals = LinkedHashSet<String>()\n\n    private var staticOffset = Int.MIN_VALUE\n    private var currentReturnType: Type = Later\n    private var currentStackFrameSymbols = ArrayList<Symbol>()\n\n    init {\n        declare(fakeIdentifier(\"pow\"), FunctionType(DoubleType, DoubleType, DoubleType))\n        declare(fakeIdentifier(\"time\"), FunctionType(UnsignedIntType, SignedIntType))\n\n        val constCharPointer = PointerType(Const(SignedCharType))\n        declare(fakeIdentifier(\"puts\"), FunctionType(VoidType, constCharPointer))\n        declare(fakeIdentifier(\"putchar\"), FunctionType(VoidType, SignedIntType))\n        declare(fakeIdentifier(\"getchar\"), FunctionType(SignedIntType))\n\n        declare(fakeIdentifier(\"malloc\"), FunctionType(VoidPointerType, UnsignedIntType))\n        declare(fakeIdentifier(\"free\"), FunctionType(VoidType, VoidPointerType))\n        declare(fakeIdentifier(\"realloc\"), FunctionType(VoidPointerType, VoidPointerType, UnsignedIntType))\n\n        declare(fakeIdentifier(\"memswap\"), FunctionType(VoidType, VoidPointerType, VoidPointerType, UnsignedIntType))\n\n        val predicate = FunctionType(SignedIntType, ConstVoidPointerType, ConstVoidPointerType).pointer()\n        declare(\n            fakeIdentifier(\"qsort\"),\n            FunctionType(VoidType, VoidPointerType, UnsignedIntType, UnsignedIntType, predicate)\n        )\n        declare(\n            fakeIdentifier(\"bsearch\"),\n            FunctionType(\n                VoidPointerType, ConstVoidPointerType, ConstVoidPointerType, UnsignedIntType, UnsignedIntType, predicate\n            )\n        )\n\n        declare(fakeIdentifier(\"strlen\"), FunctionType(UnsignedIntType, constCharPointer))\n        declare(fakeIdentifier(\"strcmp\"), FunctionType(SignedIntType, constCharPointer, constCharPointer))\n\n        translationUnit.externalDeclarations.forEach {\n            when (it) {\n                is FunctionDefinition -> it.typeCheck()\n                is Declaration -> it.typeCheck()\n            }\n        }\n    }\n\n    private var currentDeclarationIsStatic = false\n\n    private fun declare(name: Token, type: Type): Symbol {\n        return if (symbolTable.atGlobalScope()) {\n            declareStatic(name, type)\n        } else {\n            declareAutomatic(name, type)\n        }\n    }\n\n    private fun declareStatic(name: Token, type: Type): Symbol {\n        currentDeclarationIsStatic = true\n        val symbol = symbolTable.declare(name, type, staticOffset)\n        staticOffset += type.count()\n        return symbol\n    }\n\n    private fun declareAutomatic(name: Token, type: Type): Symbol {\n        currentDeclarationIsStatic = false\n        val symbol = symbolTable.declare(name, type, currentStackFrameSymbols.nextOffset())\n        if (symbol.type.requiresStorage()) {\n            currentStackFrameSymbols.add(symbol)\n        }\n        return symbol\n    }\n\n    private fun ArrayList<Symbol>.nextOffset(): Int {\n        if (isEmpty()) return 0\n        with(last()) {\n            return offset + type.count()\n        }\n    }\n\n    private fun declareOutside(name: Token, type: Type) {\n        assert(type is FunctionType)\n        symbolTable.declareOutside(name, type, staticOffset)\n    }\n\n    fun symbolAt(position: Int): Symbol? {\n        return symbolTable.symbolAt(position)\n    }\n\n    private fun DeclarationSpecifiers.typeCheckNoStorageClass(): Type {\n        typeCheck()\n        if (storageClass != VOID) root().error(\"no storage class allowed in this context\")\n        return type\n    }\n\n    private fun DeclarationSpecifiers.typeCheck(): Type {\n        determineType()\n        applyQualifiers()\n        return type\n    }\n\n    private fun DeclarationSpecifiers.determineType() {\n        type = typeSpecifiers[typeTokens]!!\n        if (type == Later) {\n            type = when (typeTokens.first()) {\n                ENUM -> list.firstNotNullOf { it.enumType() }\n\n                STRUCT -> list.firstNotNullOf { it.structType() }\n\n                IDENTIFIER -> {\n                    val specifier = list.find { it.kind() == IDENTIFIER }\n                    val primitive = specifier as DeclarationSpecifier.Primitive\n                    val identifier = primitive.token\n                    val symbol = symbolTable.lookup(identifier)!!\n                    val alias = symbol.type as Typedef\n                    alias.aliased\n                }\n\n                else -> root().error(\"no determineType for ${typeTokens.first()}\")\n            }\n        }\n    }\n\n    private fun DeclarationSpecifiers.applyQualifiers() {\n        if (qualifiers.contains(CONST)) {\n            type = type.addConst()\n        }\n    }\n\n    private fun DeclarationSpecifier.enumType(): Type? {\n        return when (this) {\n            is DeclarationSpecifier.EnumDef -> {\n                if (name.wasProvided()) declare(name, TypedefSignedIntType)\n                var counter = 0\n                for (enumerator in body) {\n                    with(enumerator) {\n                        if (init != null) {\n                            val type = init.typeCheck()\n                            if (type !is ArithmeticType || !type.isIntegral()) {\n                                init.root().error(\"enumeration constant must be an integral number\")\n                            }\n                            val value =\n                                init.value ?: init.root().error(\"enumeration constant must be a compile-time constant\")\n\n                            counter = (value as ArithmeticValue).value.toInt()\n                        }\n                        declare(name, EnumerationConstant(Value.signedInt(counter)))\n                        ++counter\n                    }\n                }\n                SignedIntType\n            }\n\n            is DeclarationSpecifier.EnumRef -> SignedIntType\n\n            else -> null\n        }\n    }\n\n    private fun DeclarationSpecifier.structType(): Type? {\n        return when (this) {\n            is DeclarationSpecifier.StructDef -> {\n                val members = ArrayList<Symbol>()\n                val structType = StructType(name, members)\n                if (name.wasProvided()) declare(name, StructTag(structType))\n                var offset = 0\n                for (structDeclaration in body) {\n                    val specifierType = structDeclaration.specifiers.typeCheckNoStorageClass()\n                    for (namedDeclarator in structDeclaration.declarators) {\n                        val type = namedDeclarator.typeCheck(specifierType)\n                        validateType(namedDeclarator.name, type)\n                        members.add(Symbol(namedDeclarator.name, type, offset))\n                        offset += type.count()\n                    }\n                }\n                structType.makeComplete()\n            }\n\n            is DeclarationSpecifier.StructRef -> {\n                val temp = symbolTable.lookup(name) ?: name.error(\"undefined struct $name\")\n                (temp.type as StructTag).structType\n            }\n\n            else -> null\n        }\n    }\n\n    private fun NamedDeclarator.typeCheck(specifierType: Type): Type {\n        type = declarator.type(specifierType)\n        return type\n    }\n\n    private fun FunctionParameter.typeCheck(): Type {\n        with(namedDeclarator) {\n            typeCheck(specifiers.typeCheckNoStorageClass())\n            // retain const on function parameters\n            type = type.applyQualifiersTo(type.decayed())\n            return type\n        }\n    }\n\n    private fun Declarator.type(from: Type): Type {\n        return when (this) {\n            is Declarator.Identity -> from\n\n            is Declarator.Pointer -> child.type(from.pointer().let { if (qualifiers.isEmpty()) it else it.addConst() })\n\n            is Declarator.Array -> child.type(ArrayType(determineSize(), from))\n\n            is Declarator.Function -> child.type(\n                // ignore top-level const in function types\n                FunctionType(from.unqualified(), parameters.map { it.typeCheck().unqualified() })\n            )\n\n            is Declarator.Initialized -> declarator.type(from)\n        }\n    }\n\n    private fun Declarator.Array.determineSize(): Int {\n        if (size == null) return 0\n\n        val type = size.typeCheck()\n        if (type !is ArithmeticType || !type.isIntegral()) size.root().error(\"array size must be an integral number\")\n\n        val value = size.value ?: size.root().error(\"array size must be a compile-time constant\")\n\n        val size = (value as ArithmeticValue).value.toInt()\n        if (size < 1) this.size.root().error(\"non-positive array size $size\")\n\n        return size\n    }\n\n    private fun FunctionDefinition.typeCheck() {\n        val functionType = namedDeclarator.typeCheck(specifiers.typeCheckNoStorageClass()) as FunctionType\n        functionType.defined = true\n        currentReturnType = functionType.returnType\n        if (currentReturnType is StructType) {\n            // What is the lifetime of a returned struct?\n            namedDeclarator.name.error(\"cannot return structs yet\")\n        }\n        currentStackFrameSymbols = ArrayList()\n        symbolTable.scoped {\n            for (parameter in parameters) {\n                with(parameter) {\n                    if (!name.wasProvided()) name.error(\"missing parameter name in function definition\")\n                    validateType(name, type)\n                    val symbol = declare(name, type)\n                    offset = symbol.offset\n                }\n            }\n            declareOutside(namedDeclarator.name, functionType)\n            body.typeCheck()\n        }\n        if (currentStackFrameSymbols.isEmpty()) {\n            currentStackFrameSymbols.add(Symbol(missingIdentifier, SignedCharType, 0))\n        }\n        stackFrameType = StructType(namedDeclarator.name, currentStackFrameSymbols)\n    }\n\n    private fun List<Statement>.typeCheck() {\n        return forEach { it.typeCheck() }\n    }\n\n    private fun Statement.typeCheck() {\n        when (this) {\n            is Declaration -> {\n                typeCheck()\n            }\n\n            is Block -> {\n                symbolTable.scoped { statements.typeCheck() }\n            }\n\n            is ExpressionStatement -> {\n                expression.typeCheck()\n            }\n\n            is IfThenElse -> {\n                condition.typeCheck()\n                th3n.typeCheck()\n                e1se?.typeCheck()\n            }\n\n            is Switch -> {\n                control.typeCheck().unqualified().let {\n                    if (it !is ArithmeticType || !it.isIntegral()) {\n                        switch.error(\"switch control expression must be of integral type\")\n                    }\n                }\n                body.typeCheck()\n            }\n\n            is Case -> {\n                choice.typeCheck().let {\n                    if (it !is ArithmeticType || !it.isIntegral()) {\n                        case.error(\"case label must be an integral constant\")\n                    }\n                    choice.value ?: case.error(\"case label must be a compile-time constant\")\n                }\n                body.typeCheck()\n            }\n\n            is Default -> {\n                body.typeCheck()\n            }\n\n            is While -> {\n                condition.typeCheck()\n                body.typeCheck()\n            }\n\n            is Do -> {\n                body.typeCheck()\n                condition.typeCheck()\n            }\n\n            is For -> {\n                symbolTable.scoped {\n                    init?.typeCheck()\n                    condition?.typeCheck()\n                    update?.typeCheck()\n                    body.typeCheck()\n                }\n            }\n\n            is LabeledStatement -> {\n                statement.typeCheck()\n            }\n\n            is Goto -> {\n            }\n\n            is Continue -> {\n            }\n\n            is Break -> {\n            }\n\n            is Return -> {\n                if (result == null) {\n                    if (currentReturnType !== VoidType) r3turn.error(\"missing return value\")\n                } else {\n                    checkAssignmentCompatibility(currentReturnType, result.root(), result.typeCheck())\n                }\n            }\n\n            is Assert -> {\n                if (condition is Assignment) condition.root().error(\"= is assignment, did you mean == instead?\")\n                condition.typeCheck()\n            }\n\n            else -> error(\"no typeCheck for $this\")\n        }\n    }\n\n    private fun Declaration.typeCheck() {\n        val specifierType = specifiers.typeCheck()\n        for (namedDeclarator in namedDeclarators) {\n            val name = namedDeclarator.name\n            val type = namedDeclarator.typeCheck(specifierType)\n            when (specifiers.storageClass) {\n                TYPEDEF -> declare(name, Typedef(type))\n                STATIC -> declareStatic(name, type)\n                else -> declare(name, type)\n            }\n            namedDeclarator.offset = symbolTable.lookup(namedDeclarator.name)!!.offset\n            val declarator = namedDeclarator.declarator\n            if (declarator !is Declarator.Initialized) {\n                if (type is ArrayType && type.size == 0) {\n                    name.error(\"missing array size or initializer\")\n                }\n                if (type !is FunctionType) validateType(name, type)\n            } else {\n                val init = declarator.init\n                if (type is ArrayType && type.size == 0) {\n                    if (init is InitializerList) {\n                        type.size = init.list.size\n                    } else if (init is ExpressionInitializer && init.expression is StringLiteral) {\n                        type.size = init.expression.literal.text.length + 1\n                        init.expression.type = type\n                    }\n                    if (currentDeclarationIsStatic) staticOffset += type.count()\n                }\n                typeCheck(type, init)\n            }\n        }\n    }\n\n    private fun typeCheck(qualified: Type, init: Initializer) {\n        val type = qualified.unqualified()\n        when (init) {\n            is ExpressionInitializer -> {\n                if (init.expression is StringLiteral && type is ArrayType && type.elementType == SignedCharType) {\n                    if (type.size <= init.expression.literal.text.length) {\n                        init.expression.root().error(\"string literal too long\")\n                    }\n                } else {\n                    init.expression.typeCheck()\n                    if (currentDeclarationIsStatic && init.expression.value == null && init.expression !is StringLiteral) {\n                        init.expression.root().error(\"static initializers must be compile-time constants\")\n                    }\n                    checkAssignmentCompatibility(type, init.expression.root(), init.expression.type)\n                }\n            }\n\n            is InitializerList -> when (type) {\n                is ArrayType -> {\n                    val size = type.size\n                    if (size < init.list.size) init.list[size].root().error(\"too many initializers for $type\")\n                    if (size > init.list.size) init.list.last().root().error(\"not enough initializers for $type\")\n                    init.list.forEach { typeCheck(type.elementType, it) }\n                }\n\n                is StructType -> {\n                    val size = type.members.size\n                    if (size < init.list.size) init.list[size].root().error(\"too many initializers for $type\")\n                    if (size > init.list.size) init.list.last().root().error(\"not enough initializers for $type\")\n                    for ((member, initializer) in type.members.zip(init.list)) {\n                        typeCheck(member.type, initializer)\n                    }\n                }\n\n                else -> init.openBrace.error(\"cannot initialize $type with braces\")\n            }\n        }\n    }\n\n    private var sizeofNesting = 0\n\n    private inline fun sizeofContext(f: () -> Unit) {\n        ++sizeofNesting\n        try {\n            f()\n        } finally {\n            --sizeofNesting\n        }\n    }\n\n    private inline fun <T : Unary> T.determineValue(f: (Value) -> Value) {\n        if (sizeofNesting == 0) {\n            val v = operand.value\n            if (v != null) {\n                value = f(v)\n            }\n        }\n    }\n\n    private inline fun <T : Binary> T.determineValue(f: (Value, Value) -> Value) {\n        if (sizeofNesting == 0) {\n            val v = left.value\n            if (v != null) {\n                val w = right.value\n                if (w != null) {\n                    value = f(v, w)\n                }\n            }\n        }\n    }\n\n    private fun Token.integer(): ArithmeticValue {\n        var radix = 10\n        var start = 0\n        if (text[0] == '0' && text.length >= 2) {\n            when (text[1]) {\n                'x', 'X' -> {\n                    radix = 16\n                    start = 2\n                }\n\n                'b', 'B' -> {\n                    radix = 2\n                    start = 2\n                }\n\n                else -> {\n                    radix = 8\n                    start = 1\n                }\n            }\n        }\n        try {\n            val x = text.substring(start).toLong(radix)\n            if (x <= 0x7fffffff) return Value.signedInt(x.toInt())\n            if (x <= 0xffffffff) return Value.unsignedInt(x.toInt())\n        } catch (_: NumberFormatException) {\n        }\n        error(\"integer literal $text is too large, allowed maximum is 4294967295\")\n    }\n\n    private fun Expression.typeCheck(): Type {\n        type = when (this) {\n            is Constant -> {\n                val constant = constant\n                val temp = when (constant.kind) {\n                    DOUBLE_CONSTANT -> Value.double(constant.text.toDouble())\n\n                    FLOAT_CONSTANT -> Value.float(constant.text.toFloat())\n\n                    INTEGER_CONSTANT -> constant.integer()\n\n                    CHARACTER_CONSTANT -> Value.signedInt(constant.text[0].code.toByte().toInt())\n\n                    else -> error(\"no value for $this\")\n                }\n                value = temp\n                temp.type\n            }\n\n            is StringLiteral -> {\n                isLocator = true\n                if (sizeofNesting == 0) {\n                    stringLiterals.add(literal.text)\n                }\n                ArrayType(literal.text.length + 1, SignedCharType)\n            }\n\n            is Identifier -> {\n                val symbol = symbolTable.lookup(name)\n                if (symbol == null) {\n                    val symbol = symbolTable.lookupInClosedScopes(name)\n                    if (symbol != null) {\n                        name.error(\"symbol $name no longer in scope\", symbol.name)\n                    }\n                    val functionToken = functionTokens[name.text]\n                    if (functionToken != null && functionToken.start > name.start) {\n                        name.error(\"must declare function before use\", functionToken)\n                    }\n                    val bestMatches = Levenshtein.bestMatches(name.text, symbolTable.names().asIterable())\n                    if (bestMatches.size == 1) {\n                        val bestMatch = bestMatches.first()\n                        val prefix = bestMatch.commonPrefixWith(name.text)\n                        name.error(\"undeclared symbol $name, did you mean $bestMatch?\", prefix.length)\n                    } else {\n                        val commaSeparated = bestMatches.joinToString(\", \")\n                        name.error(\"undeclared symbol $name, best matches: $commaSeparated\")\n                    }\n                }\n\n                this.symbol = symbol\n                symbol.usages.add(this)\n\n                if (symbol.type is EnumerationConstant) {\n                    value = symbol.type.value\n                    SignedIntType\n                } else {\n                    isLocator = (symbol.type !is FunctionType)\n                    symbol.type\n                }\n            }\n\n            is PrintfCall -> {\n                checkPrintfFormatString()\n                SignedIntType\n            }\n\n            is ScanfCall -> {\n                arguments.forEach {\n                    val type = it.typeCheck().decayed()\n                    if (type !is PointerType) it.root().error(\"missing &\")\n                    if (type.referencedType is ArrayType && type.referencedType.elementType === SignedCharType) {\n                        it.root().error(\"redundant &\")\n                    }\n                }\n                SignedIntType\n            }\n\n            is Postfix -> {\n                val operandType = operand.typeCheck()\n                if (operandType.isConst()) operator.error(\"const\", \"$operator\")\n                if (!operand.isLocator) operator.error(\"value\", \"$operator\")\n                if ((operandType is ArithmeticType) || (operandType is PointerType)) {\n                    operandType\n                } else {\n                    operator.error(\"$operandType\", \"$operator\")\n                }\n            }\n\n            is Subscript -> {\n                isLocator = true\n                val leftType = left.typeCheck().decayed()\n                val rightType = right.typeCheck().decayed()\n                if ((leftType is PointerType) && (rightType is ArithmeticType)) {\n                    leftType.referencedType\n                } else if ((leftType is ArithmeticType) && (rightType is PointerType)) {\n                    rightType.referencedType\n                } else {\n                    operator.error(\"$leftType\", \"[$rightType]\")\n                }\n            }\n\n            is FunctionCall -> {\n                val functionPointerType = function.typeCheck().decayed()\n                if (functionPointerType !is PointerType) function.root().error(\"$functionPointerType is not a function\")\n                val functionType = functionPointerType.referencedType\n                if (functionType !is FunctionType) function.root().error(\"$functionType is not a function\")\n\n                val parameterTypes = functionType.parameters\n                val nParameters = parameterTypes.size\n                val nArguments = arguments.size\n                if (nParameters != nArguments) function.root()\n                    .error(\"function takes $nParameters arguments, not $nArguments\")\n                for ((parameterType, argument) in parameterTypes.zip(arguments)) {\n                    checkAssignmentCompatibility(parameterType, argument.root(), argument.typeCheck())\n                }\n                functionType.returnType\n            }\n\n            is DirectMemberAccess -> {\n                isLocator = true\n                val leftType = left.typeCheck()\n                val structType = leftType.unqualified()\n\n                if (structType is StructType) {\n                    val member = structType.member(right) ?: right.error(\"$right is not a member of $structType\")\n                    leftType.applyQualifiersTo(member.type)\n                } else if (leftType is PointerType && leftType.referencedType.unqualified() is StructType) {\n                    dot.error(\"replace . with -> for indirect member access\")\n                } else {\n                    left.root().error(\"$structType is not a struct\")\n                }\n            }\n\n            is IndirectMemberAccess -> {\n                isLocator = true\n                val leftPointerType = left.typeCheck().decayed()\n                if (leftPointerType is StructType) arrow.error(\"replace -> with . for direct member access\")\n                if (leftPointerType !is PointerType) left.root().error(\"$leftPointerType is not a struct pointer\")\n                val leftType = leftPointerType.referencedType\n                val structType = leftType.unqualified()\n\n                if (structType is StructType) {\n                    val member = structType.member(right) ?: right.error(\"$right is not a member of $structType\")\n                    leftType.applyQualifiersTo(member.type)\n                } else {\n                    left.root().error(\"$structType is not a struct\")\n                }\n            }\n\n            is Prefix -> {\n                val operandType = operand.typeCheck()\n                if (operandType.isConst()) operator.error(\"${operator}const\")\n                if (!operand.isLocator) operator.error(\"${operator}value\")\n                if ((operandType is ArithmeticType) || (operandType is PointerType)) {\n                    operandType\n                } else {\n                    operator.error(\"${operator}$operandType\")\n                }\n            }\n\n            is Reference -> {\n                val operandType = operand.typeCheck()\n                if (operandType !is FunctionType) {\n                    if (!operand.isLocator) operator.error(\"${operator}value\")\n                } else if (operand is Identifier) {\n                    value = FunctionDesignator(operand.name, operandType).decayed()\n                }\n                PointerType(operandType)\n            }\n\n            is Dereference -> {\n                val operandType = operand.typeCheck().decayed()\n                if (operandType !is PointerType) operator.error(\"${operator}$operandType\")\n                isLocator = (operandType.referencedType !is FunctionType)\n                operandType.referencedType\n            }\n\n            is UnaryPlus -> {\n                val operandType = operand.typeCheck().decayed()\n                if (operandType !is ArithmeticType) operator.error(\"${operator}$operandType\")\n                this.determineValue(::unaryPlus)\n                SignedIntType.max(operandType)\n            }\n\n            is UnaryMinus -> {\n                val operandType = operand.typeCheck().decayed()\n                if (operandType !is ArithmeticType) operator.error(\"${operator}$operandType\")\n                this.determineValue(::unaryMinus)\n                SignedIntType.max(operandType)\n            }\n\n            is BitwiseNot -> {\n                val operandType = operand.typeCheck().decayed()\n                if (operandType !is ArithmeticType || !operandType.isIntegral()) operator.error(\"${operator}$operandType\")\n                this.determineValue(::bitwiseNot)\n                SignedIntType.max(operandType)\n            }\n\n            is LogicalNot -> {\n                val operandType = operand.typeCheck().decayed()\n                if (operandType !is ArithmeticType) operator.error(\"${operator}$operandType\")\n                this.determineValue(::logicalNot)\n                SignedIntType\n            }\n\n            is SizeofType -> {\n                operandType = declarator.type(specifiers.typeCheckNoStorageClass())\n                val size = operandType.sizeof()\n                if (size == 0) operator.error(\"sizeof requires object type\")\n                value = Value.unsignedInt(size)\n                UnsignedIntType\n            }\n\n            is SizeofExpression -> {\n                sizeofContext { operand.typeCheck() }\n                val size = operand.type.sizeof()\n                if (size == 0) operator.error(\"sizeof requires object type\")\n                value = Value.unsignedInt(size)\n                UnsignedIntType\n            }\n\n            is Multiplicative -> {\n                val leftType = left.typeCheck().decayed()\n                val rightType = right.typeCheck().decayed()\n                if ((leftType is ArithmeticType) && (rightType is ArithmeticType)) {\n                    this.determineValue { a, b -> multiplicative(a, operator, b) }\n                    leftType.usualArithmeticConversions(rightType)\n                } else {\n                    operator.error(\"$leftType \", \"$operator $rightType\")\n                }\n            }\n\n            is Plus -> {\n                val leftType = left.typeCheck().decayed()\n                val rightType = right.typeCheck().decayed()\n                if ((leftType is ComparablePointerType) && (rightType is ArithmeticType)) {\n                    leftType\n                } else if ((leftType is ArithmeticType) && (rightType is ComparablePointerType)) {\n                    rightType\n                } else if ((leftType is ArithmeticType) && (rightType is ArithmeticType)) {\n                    this.determineValue(::plus)\n                    leftType.usualArithmeticConversions(rightType)\n                } else {\n                    operator.error(\"$leftType \", \"$operator $rightType\")\n                }\n            }\n\n            is Minus -> {\n                val leftType = left.typeCheck().decayed()\n                val rightType = right.typeCheck().decayed()\n                if ((leftType is ComparablePointerType) && (rightType is ArithmeticType)) {\n                    leftType\n                } else if ((leftType is ComparablePointerType) && (rightType is ComparablePointerType)) {\n                    SignedIntType\n                } else if ((leftType is ArithmeticType) && (rightType is ArithmeticType)) {\n                    this.determineValue(::minus)\n                    leftType.usualArithmeticConversions(rightType)\n                } else {\n                    operator.error(\"$leftType \", \"$operator $rightType\")\n                }\n            }\n\n            is Shift -> {\n                val leftType = left.typeCheck().decayed()\n                val rightType = right.typeCheck().decayed()\n                if ((leftType is ArithmeticType && leftType.isIntegral()) && (rightType is ArithmeticType && rightType.isIntegral())) {\n                    val typ = leftType.integralPromotions()\n                    this.determineValue { a, b -> shift(a, operator, b, typ) }\n                    typ\n                } else {\n                    operator.error(\"$leftType \", \"$operator $rightType\")\n                }\n            }\n\n            is RelationalEquality -> {\n                val leftType = left.typeCheck().decayed()\n                val rightType = right.typeCheck().decayed()\n                if ((leftType is ComparablePointerType) && (rightType is ComparablePointerType)) {\n                    SignedIntType\n                } else if ((leftType is ArithmeticType) && (rightType is ArithmeticType)) {\n                    this.determineValue { a, b ->\n                        relationalEquality(a as ArithmeticValue, operator, b as ArithmeticValue)\n                    }\n                    SignedIntType\n                } else {\n                    operator.error(\"$leftType \", \"$operator $rightType\")\n                }\n            }\n\n            is Bitwise -> {\n                val leftType = left.typeCheck().decayed()\n                val rightType = right.typeCheck().decayed()\n                if ((leftType is ArithmeticType && leftType.isIntegral()) && (rightType is ArithmeticType && rightType.isIntegral())) {\n                    val typ = leftType.usualArithmeticConversions(rightType)\n                    this.determineValue { a, b -> bitwise(a, operator, b, typ) }\n                    typ\n                } else {\n                    operator.error(\"$leftType \", \"$operator $rightType\")\n                }\n            }\n\n            is Logical -> {\n                val leftType = left.typeCheck().decayed()\n                val rightType = right.typeCheck().decayed()\n                if ((leftType is ArithmeticType) && (rightType is ArithmeticType)) {\n                    this.determineValue { a, b ->\n                        when (operator.kind) {\n                            AMPERSAND_AMPERSAND -> {\n                                if ((a as ArithmeticValue).isFalse()) Value.ZERO\n                                else (b as ArithmeticValue).normalizeBool()\n                            }\n\n                            BAR_BAR -> {\n                                if ((a as ArithmeticValue).isTrue()) Value.ONE\n                                else (b as ArithmeticValue).normalizeBool()\n                            }\n\n                            else -> error(\"no evaluate for $operator\")\n                        }\n                    }\n                    SignedIntType\n                } else {\n                    operator.error(\"$leftType \", \"$operator $rightType\")\n                }\n            }\n\n            is Conditional -> {\n                condition.typeCheck().decayed()\n                val a = th3n.typeCheck().decayed()\n                val b = e1se.typeCheck().decayed()\n                if (a is ArithmeticType && b is ArithmeticType) {\n                    a.usualArithmeticConversions(b)\n                } else if (a is VoidType && b is VoidType) {\n                    VoidType\n                } else if (a is PointerType && b is PointerType) {\n                    if (a.referencedType == b.referencedType) {\n                        a\n                    } else {\n                        colon.error(\"$a \", \": $b\")\n                    }\n                } else if (a is ComparablePointerType && b is ComparablePointerType) {\n                    // one or more void pointers\n                    VoidPointerType\n                } else {\n                    colon.error(\"$a \", \": $b\")\n                }\n            }\n\n            is Cast -> {\n                val targetType = declarator.type(specifiers.typeCheckNoStorageClass()).unqualified()\n                val sourceType = operand.typeCheck()\n                checkAssignmentCompatibility(targetType, operator, sourceType)\n                this.determineValue { targetType.cast(it) }\n                targetType\n            }\n\n            is Assignment -> {\n                val leftType = left.typeCheck()\n                if (leftType.isConst()) operator.error(\"const \", \"$operator \")\n                if (!left.isLocator) operator.error(\"value \", \"$operator \")\n                val rightType = right.typeCheck()\n                checkAssignmentCompatibility(leftType, operator, rightType)\n                leftType\n            }\n\n            is PlusAssignment -> {\n                typeCheckPlusMinusAssignment()\n            }\n\n            is MinusAssignment -> {\n                typeCheckPlusMinusAssignment()\n            }\n\n            is Comma -> {\n                left.typeCheck()\n                right.typeCheck().decayed()\n            }\n\n            else -> error(\"no typeCheck for $this\")\n        }\n        return type\n    }\n\n    private fun Binary.typeCheckPlusMinusAssignment(): Type {\n        val leftType = left.typeCheck()\n        if (leftType.isConst()) operator.error(\"const \", \"$operator \")\n        if (!left.isLocator) operator.error(\"value \", \"$operator \")\n        val rightType = right.typeCheck().decayed()\n        if ((leftType is ArithmeticType) && (rightType is ArithmeticType)) {\n            return leftType\n        } else if ((leftType is ComparablePointerType) && (rightType is ArithmeticType)) {\n            return leftType\n        } else {\n            operator.error(\"$leftType \", \"$operator $rightType\")\n        }\n    }\n\n    private fun PrintfCall.checkPrintfFormatString() {\n        try {\n            val args = arguments.iterator()\n            val fmt = format.text\n            var k = fmt.indexOf('%')\n            while (k != -1) {\n                if (fmt[++k] != '%') {\n                    k = fmt.skipDigits(k) // width\n                    if (fmt[k] == '.') {\n                        val dot = k\n                        k = fmt.skipDigits(k + 1) // precision\n                        if (fmt[k] !in \"eEfgGs\") format.stringErrorAt(dot, \". only works inside %e %E %f %g %G %s\")\n                    }\n                    if (fmt[k] !in \"ciudoxXeEfgGspn\") format.stringErrorAt(k, \"illegal conversion specifier\")\n                    if (!args.hasNext()) format.stringErrorAt(k, \"missing argument after format string\")\n                    val arg = args.next()\n                    checkPrintfConversionSpecifier(fmt[k], arg.typeCheck().decayed(), arg.root())\n                }\n                k = fmt.indexOf('%', k + 1)\n            }\n            if (args.hasNext()) args.next().root().error(\"missing conversion specifier in format string\")\n        } catch (ex: StringIndexOutOfBoundsException) {\n            throw Diagnostic(format.end - 1, \"incomplete conversion specifier\")\n        }\n    }\n\n    private fun checkPrintfConversionSpecifier(specifier: Char, type: Type, where: Token) {\n        when (specifier) {\n            'c', 'i', 'u', 'd', 'o', 'x', 'X' -> if (type !is ArithmeticType || !type.isIntegral()) {\n                where.error(\"%$specifier expects integral type, not $type\")\n            }\n\n            'e', 'E', 'f', 'g', 'G' -> if (type !is ArithmeticType || type.isIntegral()) {\n                where.error(\"%$specifier expects floating type, not $type\")\n            }\n\n            's' -> if (type !is PointerType || type.referencedType.unqualified() !== SignedCharType) {\n                where.error(\"%$specifier expects string, not $type\")\n            }\n\n            'p' -> if (type !is ComparablePointerType) {\n                where.error(\"%$specifier expects pointer, not $type\")\n            }\n\n            'n' -> where.error(\"%$specifier not implemented yet\")\n\n            else -> where.error(\"illegal conversion specifier %$specifier\")\n        }\n    }\n\n    private fun checkAssignmentCompatibility(left: Type, operator: Token, right: Type) {\n        if (!left.canCastFrom(right)) {\n            operator.error(\"$right\\n cannot be converted to \\n$left\")\n        }\n    }\n\n    private fun validateType(name: Token, type: Type) {\n        if (!type.isComplete()) name.error(\"incomplete type $type\")\n        when (type) {\n            is ArrayType -> validateType(name, type.elementType)\n\n            is PointerType -> {\n                val t = type.referencedType\n                if (t !is StructType && t !is FunctionType) validateType(name, t)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/semantic/TypeSpecifiers.kt",
    "content": "package semantic\n\nimport semantic.types.*\nimport syntax.lexer.TokenKind.*\nimport syntax.lexer.TokenKindSet\n\nval enumStructUnion = TokenKindSet.of(ENUM, STRUCT, UNION)\nval storageClasses = TokenKindSet.of(TYPEDEF, EXTERN, STATIC, AUTO, REGISTER)\n\nval typeSpecifierIdentifier = TokenKindSet.of(IDENTIFIER)\n\nval typeSpecifiers = mapOf(\n    TokenKindSet.of(VOID) to VoidType,\n    TokenKindSet.of(CHAR) to SignedCharType,\n    TokenKindSet.of(SIGNED, CHAR) to SignedCharType,\n    TokenKindSet.of(UNSIGNED, CHAR) to UnsignedCharType,\n    TokenKindSet.of(SHORT) to SignedShortType,\n    TokenKindSet.of(SHORT, INT) to SignedShortType,\n    TokenKindSet.of(SIGNED, SHORT) to SignedShortType,\n    TokenKindSet.of(SIGNED, SHORT, INT) to SignedShortType,\n    TokenKindSet.of(UNSIGNED, SHORT) to UnsignedShortType,\n    TokenKindSet.of(UNSIGNED, SHORT, INT) to UnsignedShortType,\n    TokenKindSet.of(INT) to SignedIntType,\n    TokenKindSet.of(SIGNED) to SignedIntType,\n    TokenKindSet.of(SIGNED, INT) to SignedIntType,\n    TokenKindSet.of(UNSIGNED) to UnsignedIntType,\n    TokenKindSet.of(UNSIGNED, INT) to UnsignedIntType,\n    TokenKindSet.of(LONG) to SignedIntType,\n    TokenKindSet.of(LONG, INT) to SignedIntType,\n    TokenKindSet.of(SIGNED, LONG) to SignedIntType,\n    TokenKindSet.of(SIGNED, LONG, INT) to SignedIntType,\n    TokenKindSet.of(UNSIGNED, LONG) to UnsignedIntType,\n    TokenKindSet.of(UNSIGNED, LONG, INT) to UnsignedIntType,\n    TokenKindSet.of(FLOAT) to FloatType,\n    TokenKindSet.of(DOUBLE) to DoubleType,\n    TokenKindSet.of(ENUM) to Later,\n    TokenKindSet.of(STRUCT) to Later,\n    typeSpecifierIdentifier to Later,\n)\n\nfun main() {\n    var spread = 0x1_0000_0001\n    while (!perfect(spread)) {\n        spread += 2\n    }\n    println(\"return (bits * 0x%x).ushr(32).toInt()\".format(spread))\n}\n\nprivate fun perfect(spread: Long): Boolean {\n    var set = 0\n    for (key in typeSpecifiers.keys) {\n        val hash = (key.bits * spread).ushr(32).toInt()\n        val index = hash xor (hash ushr 16) and 31\n        val mask = 1 shl index\n        if (set and mask != 0) return false\n        set = set or mask\n    }\n    return true\n}\n"
  },
  {
    "path": "src/main/kotlin/semantic/types/Arithmetic.kt",
    "content": "package semantic.types\n\nimport interpreter.ArithmeticValue\nimport interpreter.Value\nimport text.quote\n\nabstract class ArithmeticType : Type {\n    abstract fun show(value: Double): String\n\n    abstract val defaultValue: ArithmeticValue\n\n    abstract fun rank(): Int\n\n    open fun isIntegral(): Boolean = true\n\n    abstract fun trim(x: Double): Double\n\n    override fun canCastFromDecayed(source: Type): Boolean = source is ArithmeticType\n\n    override fun cast(source: Value): Value = cast(source as ArithmeticValue)\n\n    fun cast(source: ArithmeticValue): ArithmeticValue =\n        if (source.type === this) source else ArithmeticValue(trim(source.value), this)\n\n    fun integralPromotions(): ArithmeticType = this.max(SignedIntType)\n\n    fun usualArithmeticConversions(that: ArithmeticType): ArithmeticType = integralPromotions().max(that)\n\n    fun max(that: ArithmeticType): ArithmeticType = if (this.rank() < that.rank()) that else this\n\n    override fun declaration(parent: String): String = \"$this$parent\"\n}\n\nobject SignedCharType : ArithmeticType() {\n    override fun sizeof(): Int = 1\n\n    override fun show(value: Double): String = value.toInt().and(0xff).toChar().quote()\n\n    override val defaultValue: ArithmeticValue = Value.NUL\n\n    override fun rank(): Int = 0\n\n    override fun trim(x: Double): Double {\n        if (x < -128.0) throw ArithmeticException(\"char underflow $x\")\n        if (x > +127.0) throw ArithmeticException(\"char overflow $x\")\n        return x.toInt().toByte().toDouble()\n    }\n\n    override fun toString(): String = \"char\"\n}\n\nobject UnsignedCharType : ArithmeticType() {\n    override fun sizeof(): Int = 1\n\n    override fun show(value: Double): String = value.toInt().toString()\n\n    override val defaultValue: ArithmeticValue = Value.unsignedChar(0)\n\n    override fun rank(): Int = 1\n\n    override fun trim(x: Double): Double = x.toInt().and(0xff).toDouble()\n\n    override fun toString(): String = \"unsigned char\"\n}\n\nobject SignedShortType : ArithmeticType() {\n    override fun sizeof(): Int = 2\n\n    override fun show(value: Double): String = value.toInt().toString()\n\n    override val defaultValue: ArithmeticValue = Value.signedShort(0)\n\n    override fun rank(): Int = 2\n\n    override fun trim(x: Double): Double {\n        if (x < -32768.0) throw ArithmeticException(\"short underflow $x\")\n        if (x > +32767.0) throw ArithmeticException(\"short overflow $x\")\n        return x.toInt().toShort().toDouble()\n    }\n\n    override fun toString(): String = \"short\"\n}\n\nobject UnsignedShortType : ArithmeticType() {\n    override fun sizeof(): Int = 2\n\n    override fun show(value: Double): String = value.toInt().toString()\n\n    override val defaultValue: ArithmeticValue = Value.unsignedShort(0)\n\n    override fun rank(): Int = 3\n\n    override fun trim(x: Double): Double = x.toInt().and(0xffff).toDouble()\n\n    override fun toString(): String = \"unsigned short\"\n}\n\nobject SignedIntType : ArithmeticType() {\n    override fun sizeof(): Int = 4\n\n    override fun show(value: Double): String = value.toInt().toString()\n\n    override val defaultValue: ArithmeticValue by lazy { Value.signedInt(0) }\n\n    override fun rank(): Int = 4\n\n    override fun trim(x: Double): Double {\n        if (x < -2147483648.0) throw ArithmeticException(\"int underflow $x\")\n        if (x > +2147483647.0) throw ArithmeticException(\"int overflow $x\")\n        return x.toInt().toDouble()\n    }\n\n    override fun toString(): String = \"int\"\n}\n\nobject UnsignedIntType : ArithmeticType() {\n    override fun sizeof(): Int = 4\n\n    override fun show(value: Double): String = value.toLong().toString()\n\n    override val defaultValue: ArithmeticValue by lazy { Value.unsignedInt(0) }\n\n    override fun rank(): Int = 5\n\n    override fun trim(x: Double): Double = x.toLong().and(0xffffffff).toDouble()\n\n    override fun toString(): String = \"unsigned int\"\n}\n\nobject FloatType : ArithmeticType() {\n    override fun sizeof(): Int = 4\n\n    override fun show(value: Double): String = value.toFloat().toString()\n\n    override val defaultValue: ArithmeticValue = Value.float(0f)\n\n    override fun rank(): Int = 8\n\n    override fun isIntegral(): Boolean = false\n\n    override fun trim(x: Double): Double = x.toFloat().toDouble()\n\n    override fun toString(): String = \"float\"\n}\n\nobject DoubleType : ArithmeticType() {\n    override fun sizeof(): Int = 8\n\n    override fun show(value: Double): String = value.toString()\n\n    override val defaultValue: ArithmeticValue = Value.double(0.0)\n\n    override fun rank(): Int = 9\n\n    override fun isIntegral(): Boolean = false\n\n    override fun trim(x: Double): Double = x\n\n    override fun toString(): String = \"double\"\n}\n"
  },
  {
    "path": "src/main/kotlin/semantic/types/Array.kt",
    "content": "package semantic.types\n\ndata class ArrayType(var size: Int, val elementType: Type) : Type {\n    override fun sizeof(): Int = size * elementType.sizeof()\n\n    override fun sizeof(offset: Int): Int {\n        if (offset >= count()) return sizeof()\n\n        val n = elementType.count()\n        return offset / n * elementType.sizeof() + elementType.sizeof(offset % n)\n    }\n\n    override fun decayed(): Type = PointerType(elementType)\n\n    override fun count(): Int = size * elementType.count()\n\n    override fun isConst(): Boolean = elementType.isConst()\n\n    override fun addConst(): Type = if (isConst()) this else ArrayType(size, elementType.addConst())\n\n    override fun unqualified(): Type = if (isConst()) ArrayType(size, elementType.unqualified()) else this\n\n    fun dimensions(): Int = if (elementType is ArrayType) elementType.dimensions() + 1 else 1\n\n    override fun toString(): String = declaration(\"\")\n\n    override fun declaration(parent: String): String {\n        return if (parent.isPointer()) {\n            elementType.declaration(\"($parent)[$size]\")\n        } else {\n            elementType.declaration(\"$parent[$size]\")\n        }\n    }\n}\n\nfun Type.isString(): Boolean = this is ArrayType && elementType.unqualified() == SignedCharType\n"
  },
  {
    "path": "src/main/kotlin/semantic/types/Enum.kt",
    "content": "package semantic.types\n\nimport interpreter.ArithmeticValue\n\nclass EnumerationConstant(val value: ArithmeticValue) : Type {\n    override fun requiresStorage(): Boolean = false\n\n    override fun count(): Int = 0\n}\n"
  },
  {
    "path": "src/main/kotlin/semantic/types/Function.kt",
    "content": "package semantic.types\n\ndata class FunctionType(val returnType: Type, val parameters: List<Type>) : Type {\n    companion object {\n        operator fun invoke(returnType: Type, vararg parameters: Type) = FunctionType(returnType, parameters.toList())\n\n        fun declarationMarker(): FunctionType = FunctionType(VoidType)\n        val DEFINITION_MARKER: FunctionType = declarationMarker().apply { defined = true }\n    }\n\n    var defined: Boolean = false\n\n    override fun requiresStorage(): Boolean = false\n\n    override fun count(): Int = 0\n\n    override fun decayed(): Type = pointer()\n\n    override fun toString(): String = declaration(\"\")\n\n    override fun declaration(parent: String): String {\n        val params = parameters.joinToString(transform = Type::toString, prefix = \"(\", separator = \",\", postfix = \")\")\n        return if (parent.isPointer()) {\n            returnType.declaration(\"($parent)$params\")\n        } else {\n            returnType.declaration(\"$parent$params\")\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/semantic/types/Pointer.kt",
    "content": "package semantic.types\n\nimport interpreter.Value\n\ninterface ComparablePointerType : Type\n\ndata class PointerType(val referencedType: Type) : ComparablePointerType {\n    override fun sizeof(): Int = 4\n\n    override fun canCastFromDecayed(source: Type): Boolean {\n        if (source === VoidPointerType) return true\n\n        if (source === ConstVoidPointerType) return referencedType.isConst()\n\n        return canCastFromPointer(source)\n    }\n\n    private fun canCastFromPointer(source: Type): Boolean {\n        if (source !is PointerType) return false\n\n        val sourceReferenced = source.referencedType\n        return referencedType == sourceReferenced || referencedType.unqualified() == sourceReferenced\n    }\n\n    override fun cast(source: Value): Value {\n        if (!canCastFromPointer(source.type().decayed()))\n            throw AssertionError(\"${source.type()}\\n cannot be converted to \\n$this\")\n\n        return source.decayed()\n    }\n\n    override fun toString(): String = declaration(\"\")\n\n    override fun declaration(parent: String): String {\n        return referencedType.declaration(\"*$parent\")\n    }\n}\n\nobject VoidPointerType : ComparablePointerType {\n    override fun sizeof(): Int = 4\n\n    override fun canCastFromDecayed(source: Type): Boolean {\n        if (source === this) return true\n        return source is PointerType && !source.referencedType.isConst()\n    }\n\n    override fun toString(): String = \"void*\"\n\n    override fun declaration(parent: String): String = \"void*$parent\"\n}\n\nobject ConstVoidPointerType : ComparablePointerType {\n    override fun sizeof(): Int = 4\n\n    override fun canCastFromDecayed(source: Type): Boolean {\n        if (source === this || source === VoidPointerType) return true\n        return source is PointerType\n    }\n\n    override fun toString(): String = \"const void*\"\n\n    override fun declaration(parent: String): String = \"const void*$parent\"\n}\n"
  },
  {
    "path": "src/main/kotlin/semantic/types/Struct.kt",
    "content": "package semantic.types\n\nimport semantic.Symbol\nimport syntax.lexer.Token\nimport syntax.lexer.missingIdentifier\n\nabstract class CompletableType : Type {\n    private var complete = false\n\n    override fun isComplete(): Boolean = complete\n\n    fun makeComplete(): Type {\n        assert(!complete)\n        complete = true\n        return this\n    }\n}\n\nclass StructType(val name: Token, val members: List<Symbol>) : CompletableType() {\n    override fun sizeof(): Int = members.sumOf { it.type.sizeof() }\n\n    override fun sizeof(offset: Int): Int {\n        var size = 0\n        var off = offset\n        for (member in members) {\n            size += member.type.sizeof(off)\n            off -= member.type.count()\n            if (off <= 0) break\n        }\n        return size\n    }\n\n    override fun count(): Int = members.sumOf { it.type.count() }\n\n    override fun canCastFromDecayed(source: Type): Boolean = (this === source)\n\n    fun member(name: Token): Symbol? = members.find { it.name.text === name.text }\n\n    override fun toString(): String = \"struct $name\"\n\n    override fun declaration(parent: String): String = \"struct $name$parent\"\n}\n\nval StructTypeLater = StructType(missingIdentifier, emptyList())\n\nclass StructTag(val structType: StructType) : Type {\n    override fun requiresStorage(): Boolean = false\n\n    override fun count(): Int = 0\n}\n"
  },
  {
    "path": "src/main/kotlin/semantic/types/Type.kt",
    "content": "package semantic.types\n\nimport interpreter.Value\n\ninterface Type {\n    fun requiresStorage(): Boolean = true\n\n    fun isComplete(): Boolean = sizeof() > 0\n\n    fun sizeof(): Int = 0\n\n    fun sizeof(offset: Int): Int = if (offset == 0) 0 else sizeof()\n\n    fun decayed(): Type = this\n\n    fun pointer(): Type = PointerType(this)\n\n    fun count(): Int = 1\n\n    fun canCastFrom(source: Type): Boolean = canCastFromDecayed(source.decayed())\n\n    fun canCastFromDecayed(source: Type): Boolean = false\n\n    fun cast(source: Value): Value = source\n\n    fun isConst(): Boolean = false\n\n    fun addConst(): Type = Const(this)\n\n    fun unqualified(): Type = this\n\n    fun applyQualifiersTo(target: Type): Type = target\n\n    fun declaration(parent: String): String {\n        throw AssertionError(\"$javaClass.declaration($parent)\")\n    }\n\n    fun String.isPointer(): Boolean = this.isNotEmpty() && this.first() == '*'\n}\n\ndata class Const(val underlying: Type) : Type by underlying {\n    override fun pointer(): Type = PointerType(this)\n\n    override fun isConst(): Boolean = true\n\n    override fun addConst(): Type = this\n\n    override fun unqualified(): Type = underlying\n\n    override fun applyQualifiersTo(target: Type): Type = target.addConst()\n\n    override fun toString(): String = declaration(\"\")\n\n    override fun declaration(parent: String): String {\n        return if (underlying is ComparablePointerType) {\n            underlying.declaration(\"const$parent\")\n        } else {\n            \"const $underlying$parent\"\n        }\n    }\n}\n\nobject Later : Type\n"
  },
  {
    "path": "src/main/kotlin/semantic/types/Typedef.kt",
    "content": "package semantic.types\n\nclass Typedef(val aliased: Type) : Type {\n    override fun requiresStorage(): Boolean = false\n\n    override fun count(): Int = 0\n}\n\nval TypedefSignedIntType = Typedef(SignedIntType)\n\nobject MarkerIsTypedefName : Type\n\nobject MarkerNotTypedefName : Type\n"
  },
  {
    "path": "src/main/kotlin/semantic/types/Void.kt",
    "content": "package semantic.types\n\nobject VoidType : Type {\n    override fun pointer(): Type = VoidPointerType\n\n    override fun count(): Int = 0\n\n    override fun addConst(): Type = ConstVoidType\n\n    override fun toString(): String = \"void\"\n\n    override fun declaration(parent: String): String = \"void$parent\"\n}\n\nobject ConstVoidType : Type {\n    override fun pointer(): Type = ConstVoidPointerType\n\n    override fun count(): Int = 0\n\n    override fun isConst(): Boolean = true\n\n    override fun addConst(): Type = this\n\n    override fun unqualified(): Type = VoidType\n\n    override fun toString(): String = \"const void\"\n\n    override fun declaration(parent: String): String = \"const void$parent\"\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/lexer/Characters.kt",
    "content": "package syntax.lexer\n\nimport syntax.lexer.TokenKind.CHARACTER_CONSTANT\nimport syntax.lexer.TokenKind.STRING_LITERAL\n\nfun Lexer.characterConstant(): Token {\n    val executionChar = when (next()) {\n        '\\\\' -> escapeSequence()\n\n        in '\\u0020'..'\\u007e' -> current\n        in '\\u00a0'..'\\u00ff' -> current\n\n        else -> error(\"illegal character inside character constant\")\n    }\n    if (next() != '\\'') error(\"character constant must be closed by '\")\n\n    next()\n    return token(CHARACTER_CONSTANT, lexeme(), executionChar.toString())\n}\n\nfun Lexer.escapeSequence(): Char = when (next()) {\n    '\\'', '\\\"', '?', '\\\\' -> current\n\n    'a' -> '\\u0007'\n    'b' -> '\\u0008'\n    't' -> '\\u0009'\n    'n' -> '\\u000a'\n    'v' -> '\\u000b'\n    'f' -> '\\u000c'\n    'r' -> '\\u000d'\n\n    '0' -> '\\u0000'\n\n    else -> error(\"illegal escape character\")\n}\n\nfun Lexer.stringLiteral(): Token {\n    val sb = StringBuilder()\n    while (true) {\n        val executionChar = when (next()) {\n            '\\\\' -> escapeSequence()\n\n            '\\\"' -> {\n                next()\n                return token(STRING_LITERAL, lexeme(), sb.toString().intern())\n            }\n\n            in '\\u0020'..'\\u007e' -> current\n            in '\\u00a0'..'\\u00ff' -> current\n\n            else -> error(\"illegal character inside string literal\")\n        }\n        sb.append(executionChar)\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/lexer/Identifiers.kt",
    "content": "package syntax.lexer\n\nimport syntax.lexer.TokenKind.IDENTIFIER\n\ntailrec fun Lexer.identifierOrKeyword(): Token = when (next()) {\n    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',\n    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',\n    '_', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> identifierOrKeyword()\n\n    else -> {\n        val lexeme = lexeme()\n        when (val value: Any? = identifiersOrKeywords[lexeme]) {\n            is TokenKind -> verbatim(value)\n\n            is String -> token(IDENTIFIER, value)\n\n            else -> {\n                identifiersOrKeywords[lexeme] = lexeme\n                token(IDENTIFIER, lexeme)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/lexer/Lexer.kt",
    "content": "package syntax.lexer\n\nimport common.Diagnostic\n\nconst val EOF = '\\u0000'\n\nclass Lexer(private val input: String) {\n    var start: Int = -1\n        private set\n\n    var index: Int = -1\n        private set\n\n    fun startAtIndex() {\n        start = index\n    }\n\n    var current: Char = next()\n        private set\n\n    fun next(): Char {\n        current = if (++index < input.length) input[index] else EOF\n        return current\n    }\n\n    fun previous(): Char {\n        current = input[--index]\n        return current\n    }\n\n    fun lexeme(): String {\n        return input.substring(start, index)\n    }\n\n    fun token(kind: TokenKind): Token {\n        return token(kind, lexeme())\n    }\n\n    fun token(kind: TokenKind, text: String): Token {\n        return token(kind, text, text)\n    }\n\n    fun token(kind: TokenKind, source: String, text: String): Token {\n        return Token(kind, start, source, text)\n    }\n\n    fun verbatim(kind: TokenKind): Token {\n        return token(kind, kind.lexeme)\n    }\n\n    fun nextVerbatim(kind: TokenKind): Token {\n        next()\n        return verbatim(kind)\n    }\n\n    fun error(message: String): Nothing {\n        throw Diagnostic(index, message)\n    }\n\n    val identifiersOrKeywords = HashMap<String, Any>(keywords)\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/lexer/NextToken.kt",
    "content": "package syntax.lexer\n\nimport syntax.lexer.TokenKind.*\n\ntailrec fun Lexer.nextToken(): Token {\n    startAtIndex()\n    return when (current) {\n        ' ', '\\u0009', '\\u000a', '\\u000b', '\\u000c', '\\u000d' -> {\n            next()\n            nextToken()\n        }\n\n        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',\n        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',\n        '_' -> identifierOrKeyword()\n\n        '1', '2', '3', '4', '5', '6', '7', '8', '9' -> constant()\n        '0' -> zero()\n\n        '\\'' -> characterConstant()\n\n        '\\\"' -> stringLiteral()\n\n        '(' -> nextVerbatim(OPENING_PAREN)\n        ')' -> nextVerbatim(CLOSING_PAREN)\n        ',' -> nextVerbatim(COMMA)\n        '.' -> nextVerbatim(DOT)\n        ':' -> nextVerbatim(COLON)\n        ';' -> nextVerbatim(SEMICOLON)\n        '?' -> nextVerbatim(QUESTION)\n        '[' -> nextVerbatim(OPENING_BRACKET)\n        ']' -> nextVerbatim(CLOSING_BRACKET)\n        '{' -> nextVerbatim(OPENING_BRACE)\n        '}' -> nextVerbatim(CLOSING_BRACE)\n        '~' -> nextVerbatim(TILDE)\n\n        '!' -> when (next()) {\n            '=' -> nextVerbatim(BANG_EQUAL)\n            else -> verbatim(BANG)\n        }\n\n        '%' -> when (next()) {\n            '=' -> nextVerbatim(PERCENT_EQUAL)\n            else -> verbatim(PERCENT)\n        }\n\n        '&' -> when (next()) {\n            '=' -> nextVerbatim(AMPERSAND_EQUAL)\n            '&' -> nextVerbatim(AMPERSAND_AMPERSAND)\n            else -> verbatim(AMPERSAND)\n        }\n\n        '*' -> when (next()) {\n            '=' -> nextVerbatim(ASTERISK_EQUAL)\n            else -> verbatim(ASTERISK)\n        }\n\n        '+' -> when (next()) {\n            '=' -> nextVerbatim(PLUS_EQUAL)\n            '+' -> nextVerbatim(PLUS_PLUS)\n            else -> verbatim(PLUS)\n        }\n\n        '-' -> when (next()) {\n            '=' -> nextVerbatim(HYPHEN_EQUAL)\n            '-' -> nextVerbatim(HYPHEN_HYPHEN)\n            '>' -> nextVerbatim(HYPHEN_MORE)\n            else -> verbatim(HYPHEN)\n        }\n\n        '/' -> when (next()) {\n            '/' -> {\n                skipSingleLineComment()\n                nextToken()\n            }\n\n            '*' -> {\n                skipMultiLineComment()\n                nextToken()\n            }\n\n            '=' -> nextVerbatim(SLASH_EQUAL)\n\n            else -> verbatim(SLASH)\n        }\n\n        '<' -> when (next()) {\n            '=' -> nextVerbatim(LESS_EQUAL)\n\n            '<' -> when (next()) {\n                '=' -> nextVerbatim(LESS_LESS_EQUAL)\n                else -> verbatim(LESS_LESS)\n            }\n\n            else -> verbatim(LESS)\n        }\n\n        '=' -> when (next()) {\n            '=' -> nextVerbatim(EQUAL_EQUAL)\n            else -> verbatim(EQUAL)\n        }\n\n        '>' -> when (next()) {\n            '=' -> nextVerbatim(MORE_EQUAL)\n\n            '>' -> when (next()) {\n                '=' -> nextVerbatim(MORE_MORE_EQUAL)\n                else -> verbatim(MORE_MORE)\n            }\n\n            else -> verbatim(MORE)\n        }\n\n        '^' -> when (next()) {\n            '=' -> nextVerbatim(CARET_EQUAL)\n            else -> verbatim(CARET)\n        }\n\n        '|' -> when (next()) {\n            '=' -> nextVerbatim(BAR_EQUAL)\n            '|' -> nextVerbatim(BAR_BAR)\n            else -> verbatim(BAR)\n        }\n\n        EOF -> verbatim(END_OF_INPUT)\n\n        else -> error(\"illegal input character\")\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/lexer/Numbers.kt",
    "content": "package syntax.lexer\n\nimport syntax.lexer.TokenKind.*\n\nfun Lexer.constant(): Token {\n    var seenDecimalPoint = false\n    while (true) {\n        when (next()) {\n            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> {\n            }\n\n            'f', 'F' -> {\n                next()\n                return token(FLOAT_CONSTANT)\n            }\n\n            '.' -> {\n                if (seenDecimalPoint) return token(DOUBLE_CONSTANT)\n                seenDecimalPoint = true\n            }\n\n            else -> return token(if (seenDecimalPoint) DOUBLE_CONSTANT else INTEGER_CONSTANT)\n        }\n    }\n}\n\nfun Lexer.zero(): Token {\n    next()\n    if (current == 'x' || current == 'X') return hexadecimal()\n    if (current == 'b' || current == 'B') return binary()\n    previous()\n\n    var seen8or9 = false\n    var seenDecimalPoint = false\n    while (true) {\n        when (next()) {\n            '0', '1', '2', '3', '4', '5', '6', '7' -> {\n            }\n\n            '8', '9' -> {\n                seen8or9 = true\n            }\n\n            'f', 'F' -> {\n                next()\n                return token(FLOAT_CONSTANT)\n            }\n\n            '.' -> {\n                if (seenDecimalPoint) return token(DOUBLE_CONSTANT)\n                seenDecimalPoint = true\n            }\n\n            else -> {\n                if (seenDecimalPoint) return token(DOUBLE_CONSTANT)\n                if (!seen8or9) return token(INTEGER_CONSTANT)\n\n                error(\"octal literal indicated by leading digit 0 cannot contain digit 8 or 9\")\n            }\n        }\n    }\n}\n\nfun Lexer.hexadecimal(): Token {\n    while (true) {\n        when (next()) {\n            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',\n            'A', 'B', 'C', 'D', 'E', 'F',\n            'a', 'b', 'c', 'd', 'e', 'f' -> {\n            }\n\n            else -> {\n                if (index - start > 2) return token(INTEGER_CONSTANT)\n\n                error(\"hexadecimal literal indicated by leading ${lexeme()} must contain at least one digit\")\n            }\n        }\n    }\n}\n\nfun Lexer.binary(): Token {\n    while (true) {\n        when (next()) {\n            '0', '1' -> {\n            }\n\n            else -> {\n                if (index - start > 2) return token(INTEGER_CONSTANT)\n\n                error(\"binary literal indicated by leading ${lexeme()} must contain at least one digit\")\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/lexer/SkipComments.kt",
    "content": "package syntax.lexer\n\nfun Lexer.skipSingleLineComment() {\n    while (next() != '\\n') {\n        if (current == EOF) return\n    }\n    next() // skip '\\n'\n}\n\nfun Lexer.skipMultiLineComment() {\n    next() // skip '*'\n    do {\n        if (current == EOF) return\n    } while ((current != '*') or (next() != '/'))\n    next() // skip '/'\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/lexer/Token.kt",
    "content": "package syntax.lexer\n\nimport common.Diagnostic\nimport syntax.lexer.TokenKind.IDENTIFIER\nimport syntax.lexer.TokenKind.STRING_LITERAL\n\nclass Token(val kind: TokenKind, val start: Int, val source: String, val text: String) {\n    val end: Int\n        get() = start + source.length\n\n    fun withTokenKind(replacement: TokenKind): Token = Token(replacement, start, source, text)\n\n    fun tagged(): Token = Token(kind, start, source, \"#$text\".intern())\n\n    fun wasProvided(): Boolean = kind == IDENTIFIER\n\n    fun error(message: String): Nothing {\n        throw Diagnostic(start, message)\n    }\n\n    fun error(message: String, columnDelta: Int): Nothing {\n        throw Diagnostic(start, message, columnDelta = columnDelta)\n    }\n\n    fun error(before: String, after: String): Nothing {\n        throw Diagnostic(start, before + after, columnDelta = -before.length)\n    }\n\n    fun error(message: String, previous: Token): Nothing {\n        throw Diagnostic(start, message, previous.start)\n    }\n\n    //  0123 456  index\n    // \"ABC\\nXYZ\"\n    // 0123456789 origin\n    fun stringErrorAt(index: Int, message: String): Nothing {\n        assert(kind == STRING_LITERAL)\n        var origin = 1\n        repeat(index) {\n            if (source[origin] == '\\\\') ++origin\n            ++origin\n        }\n        throw Diagnostic(start + origin, message)\n    }\n\n    override fun toString(): String = source\n}\n\nfun fakeIdentifier(name: String) = Token(IDENTIFIER, Int.MIN_VALUE, name, name)\n\nval missingIdentifier = fakeIdentifier(\"\")\nval hiddenIdentifier = fakeIdentifier(\"_\")\n"
  },
  {
    "path": "src/main/kotlin/syntax/lexer/TokenKind.kt",
    "content": "package syntax.lexer\n\nenum class TokenKind(val lexeme: String) {\n    ASSERT(\"assert\"),\n    AUTO(\"auto\"),\n    BREAK(\"break\"),\n    CASE(\"case\"),\n    CHAR(\"char\"),\n    CONST(\"const\"),\n    CONTINUE(\"continue\"),\n    DEFAULT(\"default\"),\n    DO(\"do\"),\n    DOUBLE(\"double\"),\n    ELSE(\"else\"),\n    ENUM(\"enum\"),\n    EXTERN(\"extern\"),\n    FLOAT(\"float\"),\n    FOR(\"for\"),\n    GOTO(\"goto\"),\n    IF(\"if\"),\n    INT(\"int\"),\n    LONG(\"long\"),\n    REGISTER(\"register\"),\n    RETURN(\"return\"),\n    SHORT(\"short\"),\n    SIGNED(\"signed\"),\n    SIZEOF(\"sizeof\"),\n    STATIC(\"static\"),\n    STRUCT(\"struct\"),\n    SWITCH(\"switch\"),\n    TYPEDEF(\"typedef\"),\n    UNION(\"union\"),\n    UNSIGNED(\"unsigned\"),\n    VOID(\"void\"),\n    VOLATILE(\"volatile\"),\n    WHILE(\"while\"),\n\n    FLOAT_CONSTANT(\"FLOAT CONSTANT\"),\n    DOUBLE_CONSTANT(\"DOUBLE CONSTANT\"),\n    INTEGER_CONSTANT(\"INTEGER CONSTANT\"),\n    CHARACTER_CONSTANT(\"CHARACTER CONSTANT\"),\n    STRING_LITERAL(\"STRING LITERAL\"),\n    IDENTIFIER(\"IDENTIFIER\"),\n    PRINTF(\"PRINTF\"),\n    SCANF(\"SCANF\"),\n    END_OF_INPUT(\"END OF INPUT\"),\n\n    OPENING_BRACKET(\"[\"),\n    CLOSING_BRACKET(\"]\"),\n    OPENING_PAREN(\"(\"),\n    CLOSING_PAREN(\")\"),\n    DOT(\".\"),\n    HYPHEN_MORE(\"->\"),\n    PLUS_PLUS(\"++\"),\n    HYPHEN_HYPHEN(\"--\"),\n    AMPERSAND(\"&\"),\n    ASTERISK(\"*\"),\n    PLUS(\"+\"),\n    HYPHEN(\"-\"),\n    TILDE(\"~\"),\n    BANG(\"!\"),\n    SLASH(\"/\"),\n    PERCENT(\"%\"),\n    LESS_LESS(\"<<\"),\n    MORE_MORE(\">>\"),\n    LESS(\"<\"),\n    MORE(\">\"),\n    LESS_EQUAL(\"<=\"),\n    MORE_EQUAL(\">=\"),\n    EQUAL_EQUAL(\"==\"),\n    BANG_EQUAL(\"!=\"),\n    CARET(\"^\"),\n    BAR(\"|\"),\n    AMPERSAND_AMPERSAND(\"&&\"),\n    BAR_BAR(\"||\"),\n    QUESTION(\"?\"),\n    COLON(\":\"),\n    EQUAL(\"=\"),\n    ASTERISK_EQUAL(\"*=\"),\n    SLASH_EQUAL(\"/=\"),\n    PERCENT_EQUAL(\"%=\"),\n    PLUS_EQUAL(\"+=\"),\n    HYPHEN_EQUAL(\"-=\"),\n    LESS_LESS_EQUAL(\"<<=\"),\n    MORE_MORE_EQUAL(\">>=\"),\n    AMPERSAND_EQUAL(\"&=\"),\n    CARET_EQUAL(\"^=\"),\n    BAR_EQUAL(\"|=\"),\n    COMMA(\",\"),\n    OPENING_BRACE(\"{\"),\n    CLOSING_BRACE(\"}\"),\n    SEMICOLON(\";\");\n\n    override fun toString(): String = lexeme\n\n    companion object {\n        val KEYWORDS = entries.subList(ASSERT.ordinal, WHILE.ordinal + 1)\n        val OPERATORS_SEPARATORS = entries.subList(OPENING_BRACKET.ordinal, SEMICOLON.ordinal + 1)\n    }\n}\n\nval keywords: Map<String, TokenKind> = TokenKind.KEYWORDS.associateBy(TokenKind::lexeme)\n"
  },
  {
    "path": "src/main/kotlin/syntax/lexer/TokenKindSet.kt",
    "content": "package syntax.lexer\n\nimport java.lang.Long.lowestOneBit\nimport java.lang.Long.numberOfTrailingZeros\n\nprivate val TokenKind.bitmask: Long\n    get() {\n        assert(ordinal < Long.SIZE_BITS) { \"$this@$ordinal is not among the first ${Long.SIZE_BITS} enum constants\" }\n        return 1L shl ordinal\n    }\n\nclass TokenKindSet(val bits: Long) {\n    companion object {\n        val EMPTY = TokenKindSet(0L)\n\n        fun of(kind: TokenKind): TokenKindSet {\n            return TokenKindSet(kind.bitmask)\n        }\n\n        fun of(kind1: TokenKind, kind2: TokenKind): TokenKindSet {\n            return TokenKindSet(kind1.bitmask or kind2.bitmask)\n        }\n\n        fun of(kind1: TokenKind, kind2: TokenKind, kind3: TokenKind): TokenKindSet {\n            return TokenKindSet(kind1.bitmask or kind2.bitmask or kind3.bitmask)\n        }\n\n        fun of(kind1: TokenKind, kind2: TokenKind, kind3: TokenKind, kind4: TokenKind): TokenKindSet {\n            return TokenKindSet(kind1.bitmask or kind2.bitmask or kind3.bitmask or kind4.bitmask)\n        }\n\n        fun of(kind1: TokenKind, kind2: TokenKind, kind3: TokenKind, kind4: TokenKind, kind5: TokenKind): TokenKindSet {\n            return TokenKindSet(kind1.bitmask or kind2.bitmask or kind3.bitmask or kind4.bitmask or kind5.bitmask)\n        }\n    }\n\n    fun contains(kind: TokenKind): Boolean {\n        return (bits and kind.bitmask) != 0L\n    }\n\n    operator fun plus(kind: TokenKind): TokenKindSet {\n        return TokenKindSet(bits or kind.bitmask)\n    }\n\n    fun isEmpty(): Boolean {\n        return bits == 0L\n    }\n\n    fun first(): TokenKind {\n        return TokenKind.entries[numberOfTrailingZeros(bits)]\n    }\n\n    override fun equals(other: Any?): Boolean {\n        return other is TokenKindSet && this.bits == other.bits\n    }\n\n    override fun hashCode(): Int {\n        return (bits * 0x10418282f).ushr(32).toInt()\n    }\n\n    override fun toString(): String {\n        return generateSequence(bits) { b -> b xor lowestOneBit(b) }\n            .takeWhile { b -> b != 0L }\n            .map { b -> TokenKind.entries[numberOfTrailingZeros(b)] }\n            .joinToString(\", \", \"[\", \"]\")\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/parser/Autocompletion.kt",
    "content": "package syntax.parser\n\nimport common.Diagnostic\nimport syntax.lexer.Lexer\nimport syntax.lexer.TokenKind\n\nfun autocompleteIdentifier(textBeforeSelection: String): List<String> {\n    val lexer = Lexer(textBeforeSelection)\n    val parser = Parser(lexer)\n    val suffixes = parser.fittingSuffixes(textBeforeSelection)\n    val lcp = longestCommonPrefix(suffixes)\n    return if (lcp.isEmpty()) {\n        suffixes\n    } else {\n        listOf(lcp)\n    }\n}\n\nprivate fun Parser.fittingSuffixes(textBeforeSelection: String): List<String> {\n    try {\n        translationUnit()\n    } catch (diagnostic: Diagnostic) {\n        if (diagnostic.position != textBeforeSelection.length) throw diagnostic\n\n        if (previous.kind == TokenKind.IDENTIFIER && previous.end == textBeforeSelection.length) {\n            return when (beforePrevious.kind) {\n                TokenKind.DOT, TokenKind.HYPHEN_MORE -> suffixesIn(allMemberNames.asSequence())\n\n                else -> suffixesIn(symbolTable.names())\n            }\n        }\n    }\n    return emptyList()\n}\n\nprivate fun Parser.suffixesIn(names: Sequence<String>): List<String> {\n    val prefix = previous.text\n    val prefixLength = prefix.length\n\n    return names\n        .filter { it.length > prefixLength && it.startsWith(prefix) }\n        .map { it.substring(prefixLength) }\n        .toList()\n}\n\nprivate fun longestCommonPrefix(strings: List<String>): String {\n    val shortestString = strings.minByOrNull(String::length) ?: \"\"\n    shortestString.forEachIndexed { index, ch ->\n        if (!strings.all { it[index] == ch }) {\n            return shortestString.substring(0, index)\n        }\n    }\n    return shortestString\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/parser/Declarations.kt",
    "content": "package syntax.parser\n\nimport semantic.enumStructUnion\nimport semantic.storageClasses\nimport semantic.typeSpecifierIdentifier\nimport semantic.typeSpecifiers\nimport semantic.types.FunctionType\nimport semantic.types.MarkerIsTypedefName\nimport semantic.types.MarkerNotTypedefName\nimport syntax.lexer.Token\nimport syntax.lexer.TokenKind\nimport syntax.lexer.TokenKind.*\nimport syntax.lexer.TokenKindSet\nimport syntax.tree.*\n\nfun Parser.declare(namedDeclarator: NamedDeclarator, isTypedefName: Boolean) {\n    val pseudoType = when {\n        isTypedefName -> MarkerIsTypedefName\n\n        namedDeclarator.declarator.leaf() is Declarator.Function -> FunctionType.declarationMarker()\n\n        else -> MarkerNotTypedefName\n    }\n    symbolTable.declare(namedDeclarator.name, pseudoType, 0)\n}\n\nfun Parser.isTypedefName(token: Token): Boolean {\n    val symbol = symbolTable.lookup(token)\n    if (symbol == null) {\n        val taggedSymbol = symbolTable.lookup(token.tagged())\n        if (taggedSymbol != null) {\n            token.error(\"Did you forget struct/enum/union before ${token.text}?\")\n        }\n    }\n    return symbol?.type === MarkerIsTypedefName\n}\n\nfun Parser.isDeclarationSpecifier(token: Token): Boolean = when (token.kind) {\n    TYPEDEF, EXTERN, STATIC, AUTO, REGISTER,\n    CONST, VOLATILE,\n    VOID, CHAR, SHORT, INT, LONG, SIGNED, UNSIGNED, FLOAT, DOUBLE,\n    ENUM, STRUCT, UNION -> true\n\n    IDENTIFIER -> isTypedefName(token)\n\n    else -> false\n}\n\nfun Parser.declaration(): Statement {\n    val specifiers = declarationSpecifiers1declareDefTagName()\n    val isTypedef = specifiers.storageClass == TYPEDEF\n    val declarators = commaSeparatedList0(SEMICOLON) {\n        initDeclarator().apply { declare(this, isTypedef) }\n    }\n    if (current == OPENING_BRACE) {\n        val inner = declarators.last().name\n        val outer = symbolTable.currentFunction()!!.name\n        inner.error(\"cannot define function $inner inside function $outer\", outer)\n    }\n    return Declaration(specifiers, declarators).semicolon()\n}\n\nfun Parser.declarationSpecifiers1declareDefTagName(): DeclarationSpecifiers {\n    val specifiers = declarationSpecifiers1()\n    specifiers.defTagName()?.let { name ->\n        symbolTable.declare(name, MarkerNotTypedefName, 0)\n    }\n    return specifiers\n}\n\nfun Parser.declarationSpecifiers1(): DeclarationSpecifiers {\n    val specifiers = declarationSpecifiers0()\n    if (specifiers.list.isEmpty()) {\n        val symbol = symbolTable.lookup(token)\n        if (symbol != null) {\n            val taggedSymbol = symbolTable.lookup(token.tagged())\n            if (taggedSymbol != null) {\n                token.error(\"Did you forget struct/enum/union before ${token.text}?\")\n            }\n        }\n        illegalStartOf(\"declaration\")\n    }\n    return specifiers\n}\n\nfun Parser.declarationSpecifiers0(): DeclarationSpecifiers {\n    var storageClass: TokenKind = VOID\n    var qualifiers = TokenKindSet.EMPTY\n    var typeTokens = TokenKindSet.EMPTY\n    val list = ArrayList<DeclarationSpecifier>()\n\n    loop@ while (true) {\n        when (current) {\n            TYPEDEF, EXTERN, STATIC, AUTO, REGISTER ->\n                if (storageClass == VOID) {\n                    storageClass = current\n                } else {\n                    val previous = list.first { storageClasses.contains(it.kind()) }\n                    token.error(\"multiple storage class specifiers\", previous.root())\n                }\n\n            CONST, VOLATILE ->\n                if (qualifiers.contains(current)) {\n                    val previous = list.first { it.kind() == current }\n                    token.error(\"duplicate type qualifier\", previous.root())\n                } else {\n                    qualifiers += current\n                }\n\n            IDENTIFIER ->\n                if (typeTokens.isEmpty() && isTypedefName(token)) {\n                    typeTokens = typeSpecifierIdentifier\n                } else {\n                    break@loop\n                }\n\n            VOID, CHAR, SHORT, INT, LONG, SIGNED, UNSIGNED, FLOAT, DOUBLE,\n            ENUM, STRUCT, UNION ->\n                if (!typeTokens.isEmpty() && enumStructUnion.contains(typeTokens.first())) {\n                    val previous = list.first { enumStructUnion.contains(it.kind()) }\n                    token.error(\n                        \"Did you forget to terminate the previous ${previous.kind()} with a semicolon?\",\n                        previous.root()\n                    )\n                } else if (typeTokens.contains(current)) {\n                    val previous = list.first { it.kind() == current }\n                    token.error(\"duplicate type specifier\", previous.root())\n                } else {\n                    typeTokens += current\n                    if (typeTokens !in typeSpecifiers) token.error(\"illegal combination of type specifiers: $typeTokens\")\n                }\n\n            else -> break@loop\n        }\n        list.add(declarationSpecifier())\n    }\n    return DeclarationSpecifiers(list, storageClass, qualifiers, typeTokens)\n}\n\nfun Parser.declarationSpecifier(): DeclarationSpecifier = when (current) {\n    ENUM -> enumSpecifier()\n\n    STRUCT -> structSpecifier()\n\n    UNION -> notImplementedYet(\"unions\")\n\n    else -> DeclarationSpecifier.Primitive(accept())\n}\n\nfun Parser.enumSpecifier(): DeclarationSpecifier {\n    return if (next() == OPENING_BRACE) {\n        // anonymous enum\n        DeclarationSpecifier.EnumDef(token, enumBody())\n    } else {\n        val name = expect(IDENTIFIER).tagged()\n        if (current == OPENING_BRACE) {\n            // named enum\n            DeclarationSpecifier.EnumDef(name, enumBody())\n        } else {\n            DeclarationSpecifier.EnumRef(name)\n        }\n    }\n}\n\nfun Parser.enumBody(): List<Enumerator> {\n    return braced {\n        commaSeparatedList1 {\n            Enumerator(expect(IDENTIFIER), optional(EQUAL, ::assignmentExpression)).apply {\n                symbolTable.declare(name, MarkerNotTypedefName, 0)\n            }\n        }\n    }\n}\n\nfun Parser.structSpecifier(): DeclarationSpecifier {\n    return if (next() == OPENING_BRACE) {\n        // anonymous struct\n        DeclarationSpecifier.StructDef(token, structBody())\n    } else {\n        val name = expect(IDENTIFIER).tagged()\n        if (current == OPENING_BRACE) {\n            // named struct\n            DeclarationSpecifier.StructDef(name, structBody())\n        } else {\n            DeclarationSpecifier.StructRef(name)\n        }\n    }\n}\n\nfun Parser.structBody(): List<StructDeclaration> {\n    return braced {\n        list1Until(CLOSING_BRACE) {\n            StructDeclaration(declarationSpecifiers1(), commaSeparatedList1 {\n                namedDeclarator().apply { allMemberNames.add(name.text) }\n            }).semicolon()\n        }\n    }\n}\n\nfun Parser.initDeclarator(): NamedDeclarator {\n    return initDeclarator(namedDeclarator())\n}\n\nfun Parser.initDeclarator(namedDeclarator: NamedDeclarator): NamedDeclarator {\n    return if (current == EQUAL) {\n        next()\n        with(namedDeclarator) {\n            NamedDeclarator(name, Declarator.Initialized(declarator, initializer()))\n        }\n    } else {\n        namedDeclarator\n    }\n}\n\nfun Parser.initializer(): Initializer {\n    return if (current == OPENING_BRACE) {\n        InitializerList(token, braced { trailingCommaSeparatedList1(CLOSING_BRACE, ::initializer) })\n    } else {\n        ExpressionInitializer(assignmentExpression())\n    }\n}\n\nfun Parser.namedDeclarator(): NamedDeclarator {\n    if (current == ASTERISK) {\n        next()\n        val qualifiers = typeQualifierList()\n        return namedDeclarator().map { Declarator.Pointer(it, qualifiers) }\n    }\n    var temp: NamedDeclarator = when (current) {\n        OPENING_PAREN -> parenthesized(::namedDeclarator)\n\n        IDENTIFIER -> NamedDeclarator(accept(), Declarator.Identity)\n\n        else -> illegalStartOf(\"declarator\")\n    }\n    while (true) {\n        temp = when (current) {\n            OPENING_BRACKET -> temp.map { Declarator.Array(it, declaratorArray()) }\n\n            OPENING_PAREN -> temp.map { Declarator.Function(it, declaratorFunction()) }\n\n            else -> return temp\n        }\n    }\n}\n\nfun Parser.typeQualifierList(): List<Token> {\n    return collectWhile { current == CONST }\n}\n\nfun Parser.declaratorArray(): Expression? {\n    expect(OPENING_BRACKET)\n    return ::expression optionalBefore CLOSING_BRACKET\n}\n\nfun Parser.declaratorFunction(): List<FunctionParameter> {\n    return symbolTable.scoped {\n        parenthesized {\n            if (current == VOID && lookahead.kind == CLOSING_PAREN) {\n                next()\n            }\n            commaSeparatedList0(CLOSING_PAREN) {\n                val specifiers = declarationSpecifiers1declareDefTagName()\n                val declarator = parameterDeclarator()\n                if (declarator.name.wasProvided()) {\n                    declare(declarator, isTypedefName = false)\n                }\n                FunctionParameter(specifiers, declarator)\n            }\n        }\n    }\n}\n\nfun Parser.abstractDeclarator(): Declarator {\n    if (current == ASTERISK) {\n        next()\n        val qualifiers = typeQualifierList()\n        return Declarator.Pointer(abstractDeclarator(), qualifiers)\n    }\n    var temp: Declarator = when (current) {\n        OPENING_PAREN -> parenthesized(::abstractDeclarator)\n\n        IDENTIFIER -> token.error(\"identifier in abstract declarator\")\n\n        else -> Declarator.Identity\n    }\n    while (true) {\n        temp = when (current) {\n            OPENING_BRACKET -> Declarator.Array(temp, declaratorArray())\n\n            OPENING_PAREN -> Declarator.Function(temp, declaratorFunction())\n\n            else -> return temp\n        }\n    }\n}\n\nfun Parser.parameterDeclarator(): NamedDeclarator {\n    if (current == ASTERISK) {\n        next()\n        val qualifiers = typeQualifierList()\n        return parameterDeclarator().map { Declarator.Pointer(it, qualifiers) }\n    }\n    var temp: NamedDeclarator = when (current) {\n        OPENING_PAREN -> {\n            if (isDeclarationSpecifier(lookahead)) {\n                NamedDeclarator(token, Declarator.Function(Declarator.Identity, declaratorFunction()))\n            } else {\n                parenthesized(::parameterDeclarator)\n            }\n        }\n\n        IDENTIFIER -> NamedDeclarator(accept(), Declarator.Identity)\n\n        else -> NamedDeclarator(token, Declarator.Identity)\n    }\n    while (true) {\n        temp = when (current) {\n            OPENING_BRACKET -> temp.map { Declarator.Array(it, declaratorArray()) }\n\n            OPENING_PAREN -> temp.map { Declarator.Function(it, declaratorFunction()) }\n\n            else -> return temp\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/parser/Expressions.kt",
    "content": "package syntax.parser\n\nimport syntax.lexer.TokenKind\nimport syntax.lexer.TokenKind.*\nimport syntax.tree.*\n\nconst val PRECEDENCE_POSTFIX = 150\nconst val PRECEDENCE_PREFIX = 140\nconst val PRECEDENCE_COMMA = 10\n\nfun Parser.condition(): Expression {\n    return parenthesized(::expression)\n}\n\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun Parser.expression(): Expression {\n    return subexpression(outerPrecedence = 0)\n}\n\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun Parser.assignmentExpression(): Expression {\n    return subexpression(outerPrecedence = PRECEDENCE_COMMA)\n}\n\nfun Parser.functionCallArgument(): Expression {\n    if (isDeclarationSpecifier(token)) {\n        token.error(\"function call arguments require no types, \\nas opposed to function definition parameters\")\n    }\n    return subexpression(outerPrecedence = PRECEDENCE_COMMA)\n}\n\nfun Parser.subexpression(outerPrecedence: Int): Expression {\n    val nullDenotation = nullDenotations[current.ordinal] ?: illegalStartOf(\"expression\")\n\n    return subexpression(with(nullDenotation) { parse(accept()) }, outerPrecedence)\n}\n\ntailrec fun Parser.subexpression(left: Expression, outerPrecedence: Int): Expression {\n    val leftDenotation = leftDenotations[current.ordinal] ?: return left\n    if (leftDenotation.precedence <= outerPrecedence) return left\n\n    return subexpression(with(leftDenotation) { parse(left, accept()) }, outerPrecedence)\n}\n\nprivate val nullDenotations = arrayOfNulls<NullDenotation>(128).apply {\n    this[IDENTIFIER] = IdentifierDenotation\n    this[DOUBLE_CONSTANT, FLOAT_CONSTANT, INTEGER_CONSTANT, CHARACTER_CONSTANT] = ConstantDenotation\n    this[STRING_LITERAL] = StringLiteralDenotation\n    this[OPENING_PAREN] = PossibleCastDenotation\n    this[PLUS_PLUS, HYPHEN_HYPHEN, AMPERSAND, ASTERISK, PLUS, HYPHEN, TILDE, BANG] = PrefixDenotation\n    this[SIZEOF] = SizeofDenotation\n}\n\nprivate val leftDenotations = arrayOfNulls<LeftDenotation>(128).apply {\n    this[OPENING_BRACKET] = SubscriptDenotation\n    this[OPENING_PAREN] = FunctionCallDenotation\n    this[DOT] = DirectMemberDenotation\n    this[HYPHEN_MORE] = IndirectMemberDenotation\n    this[PLUS_PLUS, HYPHEN_HYPHEN] = PostfixCrementDenotation\n\n    this[ASTERISK, SLASH, PERCENT] = LeftAssociativeDenotation(130, ::Multiplicative)\n    this[PLUS] = LeftAssociativeDenotation(120, ::Plus)\n    this[HYPHEN] = LeftAssociativeDenotation(120, ::Minus)\n    this[LESS_LESS, MORE_MORE] = LeftAssociativeDenotation(110, ::Shift)\n    this[LESS, MORE, LESS_EQUAL, MORE_EQUAL] = LeftAssociativeDenotation(100, ::RelationalEquality)\n    this[EQUAL_EQUAL, BANG_EQUAL] = LeftAssociativeDenotation(90, ::RelationalEquality)\n    this[AMPERSAND] = LeftAssociativeDenotation(80, ::Bitwise)\n    this[CARET] = LeftAssociativeDenotation(70, ::Bitwise)\n    this[BAR] = LeftAssociativeDenotation(60, ::Bitwise)\n\n    this[AMPERSAND_AMPERSAND] = RightAssociativeDenotation(50, ::Logical)\n    this[BAR_BAR] = RightAssociativeDenotation(40, ::Logical)\n    this[QUESTION] = ConditionalDenotation(30)\n    this[EQUAL] = RightAssociativeDenotation(20, ::Assignment)\n    this[PLUS_EQUAL] = RightAssociativeDenotation(20, ::PlusAssignment)\n    this[HYPHEN_EQUAL] = RightAssociativeDenotation(20, ::MinusAssignment)\n    this[COMMA] = RightAssociativeDenotation(PRECEDENCE_COMMA, ::Comma)\n}\n\nprivate operator fun <V> Array<V>.set(index: TokenKind, value: V) {\n    this[index.ordinal] = value\n}\n\nprivate operator fun <V> Array<V>.set(vararg indexes: TokenKind, value: V) {\n    for (index in indexes) {\n        this[index.ordinal] = value\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/parser/ExternalDefinitions.kt",
    "content": "package syntax.parser\n\nimport semantic.types.FunctionType\nimport syntax.lexer.TokenKind.*\nimport syntax.tree.*\n\nfun Parser.translationUnit(): TranslationUnit {\n    return TranslationUnit(list1Until(END_OF_INPUT, ::externalDeclaration))\n}\n\nfun Parser.externalDeclaration(): Node {\n    val specifiers = declarationSpecifiers1declareDefTagName()\n    if (current == SEMICOLON && specifiers.isDeclaratorOptional()) {\n        return Declaration(specifiers, emptyList()).semicolon()\n    }\n    val firstNamedDeclarator = namedDeclarator()\n    if (firstNamedDeclarator.declarator.leaf() is Declarator.Function) {\n        if (current == SEMICOLON && lookahead.kind == OPENING_BRACE) {\n            token.error(\"function definitions require no semicolon\")\n        }\n        if (current == OPENING_BRACE) {\n            symbolTable.declare(firstNamedDeclarator.name, FunctionType.DEFINITION_MARKER, 0)\n            return symbolTable.rescoped {\n                braced {\n                    FunctionDefinition(specifiers, firstNamedDeclarator, list0Until(CLOSING_BRACE, ::statement), token)\n                }\n            }\n        }\n    }\n    val isTypedefName = specifiers.storageClass == TYPEDEF\n    declare(firstNamedDeclarator, isTypedefName)\n    val declarators = commaSeparatedList1(initDeclarator(firstNamedDeclarator)) {\n        initDeclarator().apply { declare(this, isTypedefName) }\n    }\n    return Declaration(specifiers, declarators).semicolon()\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/parser/LeftDenotations.kt",
    "content": "package syntax.parser\n\nimport syntax.lexer.Token\nimport syntax.lexer.TokenKind.*\nimport syntax.tree.*\n\nabstract class LeftDenotation(val precedence: Int) {\n    abstract fun Parser.parse(left: Expression, operator: Token): Expression\n}\n\nobject SubscriptDenotation : LeftDenotation(PRECEDENCE_POSTFIX) {\n    override fun Parser.parse(left: Expression, operator: Token): Expression {\n        return Subscript(left, operator, expression() before CLOSING_BRACKET)\n    }\n}\n\nobject FunctionCallDenotation : LeftDenotation(PRECEDENCE_POSTFIX) {\n    override fun Parser.parse(left: Expression, operator: Token): Expression {\n        return FunctionCall(left, commaSeparatedList0(CLOSING_PAREN, ::functionCallArgument) before CLOSING_PAREN)\n    }\n}\n\nobject DirectMemberDenotation : LeftDenotation(PRECEDENCE_POSTFIX) {\n    override fun Parser.parse(left: Expression, operator: Token): Expression {\n        return DirectMemberAccess(left, operator, expect(IDENTIFIER))\n    }\n}\n\nobject IndirectMemberDenotation : LeftDenotation(PRECEDENCE_POSTFIX) {\n    override fun Parser.parse(left: Expression, operator: Token): Expression {\n        return IndirectMemberAccess(left, operator, expect(IDENTIFIER))\n    }\n}\n\nobject PostfixCrementDenotation : LeftDenotation(PRECEDENCE_POSTFIX) {\n    override fun Parser.parse(left: Expression, operator: Token): Expression {\n        return Postfix(left, operator)\n    }\n}\n\nclass LeftAssociativeDenotation(precedence: Int, val factory: (Expression, Token, Expression) -> Expression) :\n    LeftDenotation(precedence) {\n    override fun Parser.parse(left: Expression, operator: Token): Expression {\n        return factory(left, operator, subexpression(precedence))\n    }\n}\n\nclass RightAssociativeDenotation(precedence: Int, val factory: (Expression, Token, Expression) -> Expression) :\n    LeftDenotation(precedence) {\n    override fun Parser.parse(left: Expression, operator: Token): Expression {\n        return factory(left, operator, subexpression(precedence - 1))\n    }\n}\n\nclass ConditionalDenotation(precedence: Int) : LeftDenotation(precedence) {\n    override fun Parser.parse(left: Expression, operator: Token): Expression {\n        return Conditional(left, operator, expression(), expect(COLON), subexpression(precedence - 1))\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/parser/NullDenotations.kt",
    "content": "package syntax.parser\n\nimport syntax.lexer.Token\nimport syntax.lexer.TokenKind.*\nimport syntax.tree.*\n\nabstract class NullDenotation {\n    abstract fun Parser.parse(token: Token): Expression\n}\n\nobject IdentifierDenotation : NullDenotation() {\n    override fun Parser.parse(token: Token): Expression {\n        return when (token.text) {\n            \"printf\" -> parenthesized { printfCall(token.withTokenKind(PRINTF)) }\n            \"scanf\" -> parenthesized { scanfCall(token.withTokenKind(SCANF)) }\n\n            else -> Identifier(token)\n        }\n    }\n\n    private fun Parser.printfCall(printf: Token): Expression {\n        val format = expect(STRING_LITERAL)\n        val arguments = if (current == COMMA) {\n            next()\n            commaSeparatedList1(::assignmentExpression)\n        } else {\n            emptyList()\n        }\n        return PrintfCall(printf, format, arguments)\n    }\n\n    private fun Parser.scanfCall(scanf: Token): Expression {\n        val format = expect(STRING_LITERAL)\n        val arguments = if (current == COMMA) {\n            next()\n            commaSeparatedList1(::assignmentExpression)\n        } else {\n            emptyList()\n        }\n        return ScanfCall(scanf, format, arguments)\n    }\n}\n\nobject ConstantDenotation : NullDenotation() {\n    override fun Parser.parse(token: Token): Expression {\n        return Constant(token)\n    }\n}\n\nobject StringLiteralDenotation : NullDenotation() {\n    override fun Parser.parse(token: Token): Expression {\n        return StringLiteral(token)\n    }\n}\n\nobject PossibleCastDenotation : NullDenotation() {\n    override fun Parser.parse(token: Token): Expression {\n        val specifiers = declarationSpecifiers0()\n        return if (specifiers.list.isEmpty()) {\n            expression() before CLOSING_PAREN\n        } else {\n            val declarator = abstractDeclarator() before CLOSING_PAREN\n            Cast(token, specifiers, declarator, subexpression(PRECEDENCE_PREFIX))\n        }\n    }\n}\n\nobject PrefixDenotation : NullDenotation() {\n    override fun Parser.parse(token: Token): Expression {\n        val operand = subexpression(PRECEDENCE_PREFIX)\n        return when (token.kind) {\n            PLUS_PLUS, HYPHEN_HYPHEN -> Prefix(token, operand)\n            AMPERSAND -> Reference(token, operand)\n            ASTERISK -> Dereference(token, operand)\n            PLUS -> UnaryPlus(token, operand)\n            HYPHEN -> UnaryMinus(token, operand)\n            TILDE -> BitwiseNot(token, operand)\n            BANG -> LogicalNot(token, operand)\n\n            else -> error(\"no parse for $token\")\n        }\n    }\n}\n\nobject SizeofDenotation : NullDenotation() {\n    override fun Parser.parse(token: Token): Expression {\n        return if (current == OPENING_PAREN && isDeclarationSpecifier(lookahead)) {\n            parenthesized { SizeofType(token, declarationSpecifiers0(), abstractDeclarator()) }\n        } else {\n            SizeofExpression(token, subexpression(PRECEDENCE_PREFIX))\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/parser/Parser.kt",
    "content": "package syntax.parser\n\nimport common.Diagnostic\nimport semantic.SymbolTable\nimport syntax.lexer.Lexer\nimport syntax.lexer.Token\nimport syntax.lexer.TokenKind\nimport syntax.lexer.TokenKind.*\nimport syntax.lexer.nextToken\n\nclass Parser(private val lexer: Lexer) {\n    var beforePrevious: Token = Token(END_OF_INPUT, 0, \"\", \"\")\n        private set\n\n    var previous: Token = Token(END_OF_INPUT, 0, \"\", \"\")\n        private set\n\n    var token: Token = lexer.nextToken()\n        private set\n\n    var current: TokenKind = token.kind\n        private set\n\n    var lookahead: Token = lexer.nextToken()\n        private set\n\n    fun next(): TokenKind {\n        beforePrevious = previous\n        previous = token\n        token = lookahead\n        current = token.kind\n        lookahead = lexer.nextToken()\n        return current\n    }\n\n    fun accept(): Token {\n        val result = token\n        next()\n        return result\n    }\n\n    fun expect(expected: TokenKind): Token {\n        if (current != expected) throw Diagnostic(previous.end, \"expected $expected\")\n        return accept()\n    }\n\n    fun <T> T.semicolon(): T {\n        expect(SEMICOLON)\n        return this\n    }\n\n    infix fun <T> T.before(expected: TokenKind): T {\n        expect(expected)\n        return this\n    }\n\n    fun illegalStartOf(rule: String): Nothing {\n        token.error(\"illegal start of $rule\")\n    }\n\n    fun notImplementedYet(feature: String): Nothing {\n        token.error(\"$feature not implemented yet\")\n    }\n\n    inline fun <T> commaSeparatedList1(first: T, parse: () -> T): List<T> {\n        val list = mutableListOf(first)\n        while (current == COMMA) {\n            next()\n            list.add(parse())\n        }\n        return list\n    }\n\n    inline fun <T> commaSeparatedList1(parse: () -> T): List<T> {\n        return commaSeparatedList1(parse(), parse)\n    }\n\n    inline fun <T> commaSeparatedList0(terminator: TokenKind, parse: () -> T): List<T> {\n        return if (current == terminator) {\n            emptyList()\n        } else {\n            commaSeparatedList1(parse)\n        }\n    }\n\n    inline fun <T> trailingCommaSeparatedList1(terminator: TokenKind, parse: () -> T): List<T> {\n        val list = mutableListOf(parse())\n        while (current == COMMA && next() != terminator) {\n            list.add(parse())\n        }\n        return list\n    }\n\n    inline fun <T> list1While(proceed: () -> Boolean, parse: () -> T): List<T> {\n        val list = mutableListOf(parse())\n        while (proceed()) {\n            list.add(parse())\n        }\n        return list\n    }\n\n    inline fun <T> list0While(proceed: () -> Boolean, parse: () -> T): List<T> {\n        return if (!proceed()) {\n            emptyList()\n        } else {\n            list1While(proceed, parse)\n        }\n    }\n\n    inline fun <T> list1Until(terminator: TokenKind, parse: () -> T): List<T> {\n        return list1While({ current != terminator }, parse)\n    }\n\n    inline fun <T> list0Until(terminator: TokenKind, parse: () -> T): List<T> {\n        return list0While({ current != terminator }, parse)\n    }\n\n    inline fun collectWhile(proceed: () -> Boolean): List<Token> {\n        return list0While(proceed, ::accept)\n    }\n\n    inline fun <T> parenthesized(parse: () -> T): T {\n        expect(OPENING_PAREN)\n        val result = parse()\n        expect(CLOSING_PAREN)\n        return result\n    }\n\n    inline fun <T> braced(parse: () -> T): T {\n        expect(OPENING_BRACE)\n        val result = parse()\n        expect(CLOSING_BRACE)\n        return result\n    }\n\n    infix fun <T> (() -> T).optionalBefore(terminator: TokenKind): T? {\n        return if (current == terminator) {\n            next()\n            null\n        } else {\n            this() before terminator\n        }\n    }\n\n    inline fun <T> optional(indicator: TokenKind, parse: () -> T): T? {\n        return if (current != indicator) {\n            null\n        } else {\n            next()\n            parse()\n        }\n    }\n\n    val symbolTable = SymbolTable()\n    val allMemberNames = HashSet<String>()\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/parser/Statements.kt",
    "content": "package syntax.parser\n\nimport common.Diagnostic\nimport syntax.lexer.Token\nimport syntax.lexer.TokenKind.*\nimport syntax.tree.*\n\nfun Parser.statement(): Statement = when (current) {\n\n    IF -> IfThenElse(accept(), condition(), statement(), optional(ELSE, ::statement))\n\n    SWITCH -> Switch(accept(), condition(), statement())\n\n    CASE -> Case(accept(), expression() before COLON, statement())\n\n    DEFAULT -> Default(accept() before COLON, statement())\n\n    WHILE -> While(accept(), condition(), statement())\n\n    DO -> Do(accept(), statement() before WHILE, condition()).semicolon()\n\n    FOR -> symbolTable.scoped {\n        val f0r = accept() before OPENING_PAREN\n        For(\n            f0r,\n            forInit(f0r),\n            ::expression optionalBefore SEMICOLON,\n            ::expression optionalBefore CLOSING_PAREN,\n            statement()\n        )\n    }\n\n    GOTO -> Goto(accept(), expect(IDENTIFIER)).semicolon()\n\n    CONTINUE -> Continue(accept()).semicolon()\n\n    BREAK -> Break(accept()).semicolon()\n\n    RETURN -> Return(accept(), ::expression optionalBefore SEMICOLON)\n\n    ASSERT -> Assert(accept(), expression()).semicolon()\n\n    TYPEDEF, EXTERN, STATIC, AUTO, REGISTER, CONST, VOLATILE,\n    VOID, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE, SIGNED, UNSIGNED,\n    STRUCT, UNION, ENUM -> declaration()\n\n    OPENING_BRACE -> symbolTable.scoped {\n        Block(token, braced {\n            list0Until(CLOSING_BRACE, ::statement)\n        })\n    }\n\n    IDENTIFIER -> when {\n        lookahead.kind == COLON -> LabeledStatement(accept() before COLON, statement())\n\n        isTypedefName(token) -> declaration()\n\n        else -> ExpressionStatement(expression()).semicolon()\n    }\n\n    SEMICOLON -> token.error(\"unexpected semicolon\")\n\n    else -> ExpressionStatement(expression()).semicolon()\n}\n\nprivate fun Parser.forInit(f0r: Token): Statement? = when (current) {\n    SEMICOLON -> null.semicolon()\n\n    TYPEDEF, EXTERN, STATIC, AUTO, REGISTER, CONST, VOLATILE,\n    VOID, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE, SIGNED, UNSIGNED,\n    STRUCT, UNION, ENUM -> forInitDeclaration(f0r)\n\n    IDENTIFIER -> when {\n        isTypedefName(token) -> forInitDeclaration(f0r)\n\n        else -> forInitExpressionStatement(f0r)\n    }\n\n    else -> forInitExpressionStatement(f0r)\n}\n\nprivate const val FOR_LOOP_SYNTAX = \"for (init; condition; update)\\n         ^          ^\\nSemicolons, NOT commas!\"\n\nprivate fun Parser.forInitDeclaration(f0r: Token): Statement {\n    try {\n        return declaration()\n    } catch (diagnostic: Diagnostic) {\n        if (diagnostic.message.endsWith(\" was already declared elsewhere\")) {\n            f0r.error(FOR_LOOP_SYNTAX)\n        } else {\n            throw diagnostic\n        }\n    }\n}\n\nprivate fun Parser.forInitExpressionStatement(f0r: Token): Statement {\n    val result = ExpressionStatement(expression())\n    if (current == CLOSING_PAREN) {\n        f0r.error(FOR_LOOP_SYNTAX)\n    }\n    return result.semicolon()\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/tree/DeclarationSpecifier.kt",
    "content": "package syntax.tree\n\nimport semantic.types.Later\nimport semantic.types.Type\nimport syntax.lexer.Token\nimport syntax.lexer.TokenKind\nimport syntax.lexer.TokenKind.ENUM\nimport syntax.lexer.TokenKind.STRUCT\nimport syntax.lexer.TokenKindSet\n\nsealed class DeclarationSpecifier : Node() {\n    abstract fun kind(): TokenKind\n\n    class Primitive(val token: Token) : DeclarationSpecifier() {\n        override fun kind(): TokenKind = token.kind\n\n        override fun root(): Token = token\n    }\n\n    class StructDef(val name: Token, val body: List<StructDeclaration>) : DeclarationSpecifier() {\n        override fun kind(): TokenKind = STRUCT\n\n        override fun root(): Token = name\n\n        override fun forEachChild(action: (Node) -> Unit) {\n            body.forEach { action(it) }\n        }\n\n        override fun toString(): String = if (name.wasProvided()) \"struct $name\" else \"struct\"\n    }\n\n    class StructRef(val name: Token) : DeclarationSpecifier() {\n        override fun kind(): TokenKind = STRUCT\n\n        override fun root(): Token = name\n\n        override fun toString(): String = \"struct $name\"\n    }\n\n    class EnumDef(val name: Token, val body: List<Enumerator>) : DeclarationSpecifier() {\n        override fun kind(): TokenKind = ENUM\n\n        override fun root(): Token = name\n\n        override fun forEachChild(action: (Node) -> Unit) {\n            body.forEach { action(it) }\n        }\n\n        override fun toString(): String = if (name.wasProvided()) \"enum $name\" else \"enum\"\n    }\n\n    class EnumRef(val name: Token) : DeclarationSpecifier() {\n        override fun kind(): TokenKind = ENUM\n\n        override fun root(): Token = name\n\n        override fun toString(): String = \"enum $name\"\n    }\n}\n\nclass StructDeclaration(val specifiers: DeclarationSpecifiers, val declarators: List<NamedDeclarator>) : Node() {\n    override fun root(): Token = specifiers.root()\n\n    override fun forEachChild(action: (Node) -> Unit) {\n        declarators.forEach { action(it) }\n    }\n\n    override fun toString(): String = specifiers.toString()\n}\n\nclass DeclarationSpecifiers(\n    val list: List<DeclarationSpecifier>,\n    val storageClass: TokenKind,\n    val qualifiers: TokenKindSet,\n    val typeTokens: TokenKindSet\n) : Node() {\n    var type: Type = Later\n\n    override fun root(): Token = list[0].root()\n\n    override fun forEachChild(action: (Node) -> Unit) {\n        list.forEach { action(it) }\n    }\n\n    override fun toString(): String = list.joinToString(\" \")\n\n    fun defTagName(): Token? {\n        when (typeTokens.first()) {\n            ENUM -> list.forEach { if (it is DeclarationSpecifier.EnumDef && it.name.wasProvided()) return it.name }\n\n            STRUCT -> list.forEach { if (it is DeclarationSpecifier.StructDef && it.name.wasProvided()) return it.name }\n\n            else -> {}\n        }\n        return null\n    }\n\n    fun isDeclaratorOptional(): Boolean {\n        return (storageClass != TokenKind.TYPEDEF) && when (typeTokens.first()) {\n            ENUM -> true\n\n            STRUCT -> list.any { it is DeclarationSpecifier.StructDef && it.name.wasProvided() }\n\n            else -> false\n        }\n    }\n}\n\nclass Enumerator(val name: Token, val init: Expression?) : Node() {\n    override fun root(): Token = name\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/tree/Declarator.kt",
    "content": "package syntax.tree\n\nimport semantic.types.Later\nimport semantic.types.Type\nimport syntax.lexer.Token\nimport syntax.lexer.hiddenIdentifier\n\nclass NamedDeclarator(val name: Token, val declarator: Declarator) : Node() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        if (declarator is Declarator.Initialized) {\n            action(declarator.init)\n        }\n    }\n\n    override fun root(): Token = name\n\n    var type: Type = Later\n    var offset: Int = 1234567890\n\n    fun hidden(): NamedDeclarator {\n        val result = NamedDeclarator(hiddenIdentifier, declarator)\n        result.type = type\n        result.offset = offset\n        return result\n    }\n\n    override fun toString(): String = \"$name : $type\"\n\n    inline fun map(f: (Declarator) -> Declarator): NamedDeclarator = NamedDeclarator(name, f(declarator))\n}\n\nclass FunctionParameter(val specifiers: DeclarationSpecifiers, val namedDeclarator: NamedDeclarator)\n\nsealed class Declarator {\n    fun leaf(): Declarator = leaf(Identity)\n\n    protected abstract fun leaf(parent: Declarator): Declarator\n\n    object Identity : Declarator() {\n        override fun leaf(parent: Declarator): Declarator = parent\n    }\n\n    class Pointer(val child: Declarator, val qualifiers: List<Token>) : Declarator() {\n        override fun leaf(parent: Declarator): Declarator = child.leaf(this)\n    }\n\n    class Array(val child: Declarator, val size: Expression?) : Declarator() {\n        override fun leaf(parent: Declarator): Declarator = child.leaf(this)\n    }\n\n    class Function(val child: Declarator, val parameters: List<FunctionParameter>) : Declarator() {\n        override fun leaf(parent: Declarator): Declarator = child.leaf(this)\n    }\n\n    class Initialized(val declarator: Declarator, val init: Initializer) : Declarator() {\n        override fun leaf(parent: Declarator): Declarator = declarator.leaf(Identity)\n    }\n}\n\nabstract class Initializer : Node()\n\nclass ExpressionInitializer(val expression: Expression) : Initializer() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        action(expression)\n    }\n\n    override fun root(): Token = expression.root()\n}\n\nclass InitializerList(val openBrace: Token, val list: List<Initializer>) : Initializer() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        list.forEach(action)\n    }\n\n    override fun root(): Token = openBrace\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/tree/Expression.kt",
    "content": "package syntax.tree\n\nimport interpreter.Value\nimport semantic.Symbol\nimport semantic.types.Later\nimport semantic.types.Type\nimport syntax.lexer.Token\n\nabstract class Expression : Node() {\n    var type: Type = Later\n    var value: Value? = null\n\n    var isLocator: Boolean = false\n\n    override fun toString(): String {\n        value?.let { value ->\n            return \"${super.toString()} : $type ${value.show()}\"\n        }\n        return \"${super.toString()} : $type\"\n    }\n}\n\nabstract class Unary(val operator: Token, val operand: Expression) : Expression() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        action(operand)\n    }\n\n    override fun root(): Token = operator\n}\n\nabstract class Binary(val left: Expression, val operator: Token, val right: Expression) : Expression() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        action(left)\n        action(right)\n    }\n\n    override fun root(): Token = operator\n}\n\nclass Constant(val constant: Token) : Expression() {\n    override fun root(): Token = constant\n}\n\nclass StringLiteral(val literal: Token) : Expression() {\n    override fun root(): Token = literal\n}\n\nclass Identifier(val name: Token) : Expression() {\n    lateinit var symbol: Symbol\n\n    override fun root(): Token = name\n}\n\nclass PrintfCall(val printf: Token, val format: Token, val arguments: List<Expression>) : Expression() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        arguments.forEach(action)\n    }\n\n    override fun root(): Token = printf\n\n    override fun toString(): String = \"printf ${format.source} : $type\"\n}\n\nclass ScanfCall(val scanf: Token, val format: Token, val arguments: List<Expression>) : Expression() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        arguments.forEach(action)\n    }\n\n    override fun root(): Token = scanf\n\n    override fun toString(): String = \"scanf ${format.source} : $type\"\n}\n\nclass Postfix(x: Expression, f: Token) : Unary(f, x)\n\nclass Subscript(x: Expression, f: Token, y: Expression) : Binary(x, f, y) {\n    override fun toString(): String = \"[] : $type\"\n}\n\nclass FunctionCall(val function: Expression, val arguments: List<Expression>) : Expression() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        action(function)\n        arguments.forEach(action)\n    }\n\n    override fun root(): Token = function.root()\n\n    override fun toString(): String = \"() : $type\"\n}\n\nclass DirectMemberAccess(val left: Expression, val dot: Token, val right: Token) : Expression() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        action(left)\n    }\n\n    override fun root(): Token = dot\n}\n\nclass IndirectMemberAccess(val left: Expression, val arrow: Token, val right: Token) : Expression() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        action(left)\n    }\n\n    override fun root(): Token = arrow\n}\n\nclass Prefix(f: Token, x: Expression) : Unary(f, x)\n\nclass Reference(f: Token, x: Expression) : Unary(f, x)\n\nclass Dereference(f: Token, x: Expression) : Unary(f, x)\n\nclass UnaryPlus(f: Token, x: Expression) : Unary(f, x)\n\nclass UnaryMinus(f: Token, x: Expression) : Unary(f, x)\n\nclass BitwiseNot(f: Token, x: Expression) : Unary(f, x)\n\nclass LogicalNot(f: Token, x: Expression) : Unary(f, x)\n\nclass Cast(operator: Token, val specifiers: DeclarationSpecifiers, val declarator: Declarator, operand: Expression) :\n    Unary(operator, operand)\n\nclass SizeofType(val operator: Token, val specifiers: DeclarationSpecifiers, val declarator: Declarator) :\n    Expression() {\n    var operandType: Type = Later\n\n    override fun root(): Token = operator\n}\n\nclass SizeofExpression(f: Token, x: Expression) : Unary(f, x)\n\nclass Multiplicative(x: Expression, f: Token, y: Expression) : Binary(x, f, y)\n\nclass Plus(x: Expression, f: Token, y: Expression) : Binary(x, f, y)\n\nclass Minus(x: Expression, f: Token, y: Expression) : Binary(x, f, y)\n\nclass Shift(x: Expression, f: Token, y: Expression) : Binary(x, f, y)\n\nclass RelationalEquality(x: Expression, f: Token, y: Expression) : Binary(x, f, y)\n\nclass Bitwise(x: Expression, f: Token, y: Expression) : Binary(x, f, y)\n\nclass Logical(x: Expression, f: Token, y: Expression) : Binary(x, f, y)\n\nclass Conditional(\n    val condition: Expression,\n    val question: Token,\n    val th3n: Expression,\n    val colon: Token,\n    val e1se: Expression\n) : Expression() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        action(condition)\n        action(th3n)\n        action(e1se)\n    }\n\n    override fun root(): Token = question\n}\n\nclass Assignment(x: Expression, f: Token, y: Expression) : Binary(x, f, y)\n\nclass PlusAssignment(x: Expression, f: Token, y: Expression) : Binary(x, f, y)\n\nclass MinusAssignment(x: Expression, f: Token, y: Expression) : Binary(x, f, y)\n\nclass Comma(x: Expression, f: Token, y: Expression) : Binary(x, f, y)\n"
  },
  {
    "path": "src/main/kotlin/syntax/tree/External.kt",
    "content": "package syntax.tree\n\nimport interpreter.BasicBlock\nimport semantic.types.StructType\nimport semantic.types.StructTypeLater\nimport syntax.lexer.Token\n\nclass TranslationUnit(val externalDeclarations: List<Node>) : Node() {\n    val functions = externalDeclarations.filterIsInstance<FunctionDefinition>()\n    val declarations: List<Declaration>\n\n    init {\n        declarations = ArrayList()\n        walkChildren({}) {\n            if (it is Declaration) {\n                declarations.add(it)\n            }\n        }\n    }\n\n    override fun forEachChild(action: (Node) -> Unit) {\n        externalDeclarations.forEach(action)\n    }\n\n    override fun root(): Token = externalDeclarations.first().root()\n\n    override fun toString(): String = \"translation unit\"\n}\n\nclass FunctionDefinition(\n    val specifiers: DeclarationSpecifiers,\n    val namedDeclarator: NamedDeclarator,\n    val body: List<Statement>,\n    val closingBrace: Token\n) : Node() {\n    fun name(): String = namedDeclarator.name.text\n\n    val parameters: List<NamedDeclarator> =\n        (namedDeclarator.declarator.leaf() as Declarator.Function).parameters.map(FunctionParameter::namedDeclarator)\n\n    var stackFrameType: StructType = StructTypeLater\n\n    lateinit var controlFlowGraph: LinkedHashMap<String, BasicBlock>\n\n    override fun forEachChild(action: (Node) -> Unit) {\n        // action(declarator)\n        body.forEach(action)\n    }\n\n    override fun root(): Token = namedDeclarator.name\n\n    override fun toString(): String = namedDeclarator.toString()\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/tree/Node.kt",
    "content": "package syntax.tree\n\nimport syntax.lexer.Token\n\nabstract class Node {\n    fun walk(enter: (Node) -> Unit, leave: (Node) -> Unit) {\n        enter(this)\n        walkChildren(enter, leave)\n        leave(this)\n    }\n\n    fun walkChildren(enter: (Node) -> Unit, leave: (Node) -> Unit) {\n        forEachChild {\n            it.walk(enter, leave)\n        }\n    }\n\n    open fun forEachChild(action: (Node) -> Unit) {\n    }\n\n    abstract fun root(): Token\n\n    override fun toString(): String = root().toString()\n}\n"
  },
  {
    "path": "src/main/kotlin/syntax/tree/Statement.kt",
    "content": "package syntax.tree\n\nimport syntax.lexer.Token\n\nabstract class Statement : Node()\n\nclass Declaration(val specifiers: DeclarationSpecifiers, val namedDeclarators: List<NamedDeclarator>) : Statement() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        namedDeclarators.forEach(action)\n    }\n\n    override fun root(): Token = specifiers.root()\n\n    override fun toString(): String = specifiers.toString()\n}\n\nclass Block(val openBrace: Token, val statements: List<Statement>) : Statement() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        statements.forEach(action)\n    }\n\n    override fun root(): Token = openBrace\n}\n\nclass ExpressionStatement(val expression: Expression) : Statement() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        action(expression)\n    }\n\n    override fun root(): Token = expression.root()\n\n    override fun toString(): String = \"${super.toString()} ;\"\n}\n\nclass IfThenElse(val iF: Token, val condition: Expression, val th3n: Statement, val e1se: Statement?) : Statement() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        action(condition)\n        action(th3n)\n        e1se?.let { action(it) }\n    }\n\n    override fun root(): Token = iF\n}\n\nclass Switch(val switch: Token, val control: Expression, val body: Statement) : Statement() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        action(control)\n        action(body)\n    }\n\n    override fun root(): Token = switch\n}\n\nclass Case(val case: Token, val choice: Expression, val body: Statement) : Statement() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        action(choice)\n        action(body)\n    }\n\n    override fun root(): Token = case\n}\n\nclass Default(val default: Token, val body: Statement) : Statement() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        action(body)\n    }\n\n    override fun root(): Token = default\n}\n\nclass While(val whi1e: Token, val condition: Expression, val body: Statement) : Statement() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        action(condition)\n        action(body)\n    }\n\n    override fun root(): Token = whi1e\n}\n\nclass Do(val d0: Token, val body: Statement, val condition: Expression) : Statement() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        action(body)\n        action(condition)\n    }\n\n    override fun root(): Token = d0\n}\n\nclass For(\n    val f0r: Token,\n    val init: Statement?,\n    val condition: Expression?,\n    val update: Expression?,\n    val body: Statement\n) : Statement() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        init?.run(action)\n        condition?.run(action)\n        update?.run(action)\n        action(body)\n    }\n\n    override fun root(): Token = f0r\n}\n\nclass Continue(val continu3: Token) : Statement() {\n    override fun root(): Token = continu3\n}\n\nclass Break(val br3ak: Token) : Statement() {\n    override fun root(): Token = br3ak\n}\n\nclass Return(val r3turn: Token, val result: Expression?) : Statement() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        result?.run(action)\n    }\n\n    override fun root(): Token = r3turn\n}\n\nclass Assert(val ass3rt: Token, val condition: Expression) : Statement() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        action(condition)\n    }\n\n    override fun root(): Token = ass3rt\n}\n\nclass LabeledStatement(val label: Token, val statement: Statement) : Statement() {\n    override fun forEachChild(action: (Node) -> Unit) {\n        action(statement)\n    }\n\n    override fun root(): Token = label\n}\n\nclass Goto(val goto: Token, val label: Token) : Statement() {\n    override fun root(): Token = goto\n}\n"
  },
  {
    "path": "src/main/kotlin/text/Char.kt",
    "content": "package text\n\nfun Char.quote(): String = when (this) {\n    '\\u0000' -> \"'\\\\0'\"\n    '\\u0007' -> \"'\\\\a'\"\n    '\\u0008' -> \"'\\\\b'\"\n    '\\u0009' -> \"'\\\\t'\"\n    '\\u000a' -> \"'\\\\n'\"\n    '\\u000b' -> \"'\\\\v'\"\n    '\\u000c' -> \"'\\\\f'\"\n    '\\u000d' -> \"'\\\\r'\"\n    ' ' -> \"' '\"\n    '!' -> \"'!'\"\n    '\"' -> \"'\\\"'\"\n    '#' -> \"'#'\"\n    '$' -> \"'$'\"\n    '%' -> \"'%'\"\n    '&' -> \"'&'\"\n    '\\'' -> \"'\\\\\\''\"\n    '(' -> \"'('\"\n    ')' -> \"')'\"\n    '*' -> \"'*'\"\n    '+' -> \"'+'\"\n    ',' -> \"','\"\n    '-' -> \"'-'\"\n    '.' -> \"'.'\"\n    '/' -> \"'/'\"\n    '0' -> \"'0'\"\n    '1' -> \"'1'\"\n    '2' -> \"'2'\"\n    '3' -> \"'3'\"\n    '4' -> \"'4'\"\n    '5' -> \"'5'\"\n    '6' -> \"'6'\"\n    '7' -> \"'7'\"\n    '8' -> \"'8'\"\n    '9' -> \"'9'\"\n    ':' -> \"':'\"\n    ';' -> \"';'\"\n    '<' -> \"'<'\"\n    '=' -> \"'='\"\n    '>' -> \"'>'\"\n    '?' -> \"'?'\"\n    '@' -> \"'@'\"\n    'A' -> \"'A'\"\n    'B' -> \"'B'\"\n    'C' -> \"'C'\"\n    'D' -> \"'D'\"\n    'E' -> \"'E'\"\n    'F' -> \"'F'\"\n    'G' -> \"'G'\"\n    'H' -> \"'H'\"\n    'I' -> \"'I'\"\n    'J' -> \"'J'\"\n    'K' -> \"'K'\"\n    'L' -> \"'L'\"\n    'M' -> \"'M'\"\n    'N' -> \"'N'\"\n    'O' -> \"'O'\"\n    'P' -> \"'P'\"\n    'Q' -> \"'Q'\"\n    'R' -> \"'R'\"\n    'S' -> \"'S'\"\n    'T' -> \"'T'\"\n    'U' -> \"'U'\"\n    'V' -> \"'V'\"\n    'W' -> \"'W'\"\n    'X' -> \"'X'\"\n    'Y' -> \"'Y'\"\n    'Z' -> \"'Z'\"\n    '[' -> \"'['\"\n    '\\\\' -> \"'\\\\\\\\'\"\n    ']' -> \"']'\"\n    '^' -> \"'^'\"\n    '_' -> \"'_'\"\n    '`' -> \"'`'\"\n    'a' -> \"'a'\"\n    'b' -> \"'b'\"\n    'c' -> \"'c'\"\n    'd' -> \"'d'\"\n    'e' -> \"'e'\"\n    'f' -> \"'f'\"\n    'g' -> \"'g'\"\n    'h' -> \"'h'\"\n    'i' -> \"'i'\"\n    'j' -> \"'j'\"\n    'k' -> \"'k'\"\n    'l' -> \"'l'\"\n    'm' -> \"'m'\"\n    'n' -> \"'n'\"\n    'o' -> \"'o'\"\n    'p' -> \"'p'\"\n    'q' -> \"'q'\"\n    'r' -> \"'r'\"\n    's' -> \"'s'\"\n    't' -> \"'t'\"\n    'u' -> \"'u'\"\n    'v' -> \"'v'\"\n    'w' -> \"'w'\"\n    'x' -> \"'x'\"\n    'y' -> \"'y'\"\n    'z' -> \"'z'\"\n    '{' -> \"'{'\"\n    '|' -> \"'|'\"\n    '}' -> \"'}'\"\n    '~' -> \"'~'\"\n\n    ' ' -> \"' '\"\n    '¡' -> \"'¡'\"\n    '¢' -> \"'¢'\"\n    '£' -> \"'£'\"\n    '¤' -> \"'¤'\"\n    '¥' -> \"'¥'\"\n    '¦' -> \"'¦'\"\n    '§' -> \"'§'\"\n    '¨' -> \"'¨'\"\n    '©' -> \"'©'\"\n    'ª' -> \"'ª'\"\n    '«' -> \"'«'\"\n    '¬' -> \"'¬'\"\n    '­' -> \"'­'\"\n    '®' -> \"'®'\"\n    '¯' -> \"'¯'\"\n    '°' -> \"'°'\"\n    '±' -> \"'±'\"\n    '²' -> \"'²'\"\n    '³' -> \"'³'\"\n    '´' -> \"'´'\"\n    'µ' -> \"'µ'\"\n    '¶' -> \"'¶'\"\n    '·' -> \"'·'\"\n    '¸' -> \"'¸'\"\n    '¹' -> \"'¹'\"\n    'º' -> \"'º'\"\n    '»' -> \"'»'\"\n    '¼' -> \"'¼'\"\n    '½' -> \"'½'\"\n    '¾' -> \"'¾'\"\n    '¿' -> \"'¿'\"\n    'À' -> \"'À'\"\n    'Á' -> \"'Á'\"\n    'Â' -> \"'Â'\"\n    'Ã' -> \"'Ã'\"\n    'Ä' -> \"'Ä'\"\n    'Å' -> \"'Å'\"\n    'Æ' -> \"'Æ'\"\n    'Ç' -> \"'Ç'\"\n    'È' -> \"'È'\"\n    'É' -> \"'É'\"\n    'Ê' -> \"'Ê'\"\n    'Ë' -> \"'Ë'\"\n    'Ì' -> \"'Ì'\"\n    'Í' -> \"'Í'\"\n    'Î' -> \"'Î'\"\n    'Ï' -> \"'Ï'\"\n    'Ð' -> \"'Ð'\"\n    'Ñ' -> \"'Ñ'\"\n    'Ò' -> \"'Ò'\"\n    'Ó' -> \"'Ó'\"\n    'Ô' -> \"'Ô'\"\n    'Õ' -> \"'Õ'\"\n    'Ö' -> \"'Ö'\"\n    '×' -> \"'×'\"\n    'Ø' -> \"'Ø'\"\n    'Ù' -> \"'Ù'\"\n    'Ú' -> \"'Ú'\"\n    'Û' -> \"'Û'\"\n    'Ü' -> \"'Ü'\"\n    'Ý' -> \"'Ý'\"\n    'Þ' -> \"'Þ'\"\n    'ß' -> \"'ß'\"\n    'à' -> \"'à'\"\n    'á' -> \"'á'\"\n    'â' -> \"'â'\"\n    'ã' -> \"'ã'\"\n    'ä' -> \"'ä'\"\n    'å' -> \"'å'\"\n    'æ' -> \"'æ'\"\n    'ç' -> \"'ç'\"\n    'è' -> \"'è'\"\n    'é' -> \"'é'\"\n    'ê' -> \"'ê'\"\n    'ë' -> \"'ë'\"\n    'ì' -> \"'ì'\"\n    'í' -> \"'í'\"\n    'î' -> \"'î'\"\n    'ï' -> \"'ï'\"\n    'ð' -> \"'ð'\"\n    'ñ' -> \"'ñ'\"\n    'ò' -> \"'ò'\"\n    'ó' -> \"'ó'\"\n    'ô' -> \"'ô'\"\n    'õ' -> \"'õ'\"\n    'ö' -> \"'ö'\"\n    '÷' -> \"'÷'\"\n    'ø' -> \"'ø'\"\n    'ù' -> \"'ù'\"\n    'ú' -> \"'ú'\"\n    'û' -> \"'û'\"\n    'ü' -> \"'ü'\"\n    'ý' -> \"'ý'\"\n    'þ' -> \"'þ'\"\n    'ÿ' -> \"'ÿ'\"\n\n    else -> \"'\\\\${Integer.toOctalString(code)}'\"\n}\n"
  },
  {
    "path": "src/main/kotlin/text/String.kt",
    "content": "package text\n\nfun String.skipDigits(start: Int): Int {\n    val n = length\n    for (i in start until n) {\n        if (this[i] !in '0'..'9') return i\n    }\n    return n\n}\n"
  },
  {
    "path": "src/main/kotlin/ui/Flexer.kt",
    "content": "package ui\n\nimport common.puts\nimport freditor.FlexerState\nimport freditor.FlexerState.EMPTY\nimport freditor.FlexerState.THIS\nimport freditor.FlexerStateBuilder\n\nobject Flexer : freditor.Flexer() {\n    private val SLASH_SLASH = FlexerState('\\n', null).setDefault(THIS)\n    private val SLASH_ASTERISK___ASTERISK_SLASH = EMPTY.tail()\n    private val SLASH_ASTERISK___ASTERISK = FlexerState('*', THIS, '/', SLASH_ASTERISK___ASTERISK_SLASH)\n    private val SLASH_ASTERISK = FlexerState('*', SLASH_ASTERISK___ASTERISK).setDefault(THIS)\n\n    private val CHAR_CONSTANT_END = EMPTY.tail()\n    private val CHAR_CONSTANT_ESCAPE = FlexerState('\\n', null)\n    private val CHAR_CONSTANT_TAIL =\n        FlexerState('\\n', null, '\\'', CHAR_CONSTANT_END, '\\\\', CHAR_CONSTANT_ESCAPE).setDefault(THIS)\n    private val CHAR_CONSTANT_HEAD = CHAR_CONSTANT_TAIL.head()\n\n    private val STRING_LITERAL_END = EMPTY.tail()\n    private val STRING_LITERAL_ESCAPE = FlexerState('\\n', null)\n    private val STRING_LITERAL_TAIL =\n        FlexerState('\\n', null, '\\\"', STRING_LITERAL_END, '\\\\', STRING_LITERAL_ESCAPE).setDefault(THIS)\n    private val STRING_LITERAL_HEAD = STRING_LITERAL_TAIL.head()\n\n    init {\n        SLASH_ASTERISK___ASTERISK.setDefault(SLASH_ASTERISK)\n        CHAR_CONSTANT_ESCAPE.setDefault(CHAR_CONSTANT_TAIL)\n        STRING_LITERAL_ESCAPE.setDefault(STRING_LITERAL_TAIL)\n    }\n\n    private val NUMBER_TAIL = FlexerState(\"..09AFXXafxx\", THIS)\n    private val NUMBER_HEAD = NUMBER_TAIL.head()\n\n    private val IDENTIFIER_TAIL = FlexerState(\"09AZ__az\", THIS)\n    private val IDENTIFIER_HEAD = IDENTIFIER_TAIL.head()\n\n    private val START = FlexerStateBuilder()\n        .set('(', OPENING_PAREN)\n        .set(')', CLOSING_PAREN)\n        .set('[', OPENING_BRACKET)\n        .set(']', CLOSING_BRACKET)\n        .set('{', OPENING_BRACE)\n        .set('}', CLOSING_BRACE)\n        .set('\\n', NEWLINE)\n        .set(' ', SPACE_HEAD)\n        .set('/', FlexerState('*', SLASH_ASTERISK, '/', SLASH_SLASH).head())\n        .set('\\'', CHAR_CONSTANT_HEAD)\n        .set('\\\"', STRING_LITERAL_HEAD)\n        .set(\"09\", NUMBER_HEAD)\n        .set(\"AZ__az\", IDENTIFIER_HEAD)\n        .build()\n        .verbatim(\n            IDENTIFIER_TAIL, \"assert\", \"auto\", \"break\", \"case\", \"char\", \"const\", \"continue\",\n            \"default\", \"do\", \"double\", \"else\", \"enum\", \"extern\", \"float\", \"for\", \"goto\", \"if\", \"int\", \"long\",\n            \"register\", \"return\", \"short\", \"signed\", \"sizeof\", \"static\", \"struct\", \"switch\", \"typedef\", \"union\",\n            \"unsigned\", \"void\", \"volatile\", \"while\"\n        )\n        .verbatim(\n            EMPTY, \"!\", \"!=\", \"%\", \"%=\", \"&\", \"&&\", \"&=\", \"*\", \"*=\", \"+\", \"++\", \"+=\", \",\", \"-\", \"--\",\n            \"-=\", \"->\", \".\", \"/\", \"/=\", \":\", \";\", \"<\", \"<<\", \"<<=\", \"<=\", \"=\", \"==\", \">\", \">=\", \">>\", \">>=\", \"?\",\n            \"^\", \"^=\", \"|\", \"|=\", \"||\", \"~\"\n        )\n        .setDefault(ERROR)\n\n    override fun start(): FlexerState = START\n\n    override fun pickColorForLexeme(previousState: FlexerState, endState: FlexerState): Int {\n        return lexemeColors[endState] ?: 0x000000\n    }\n\n    private val lexemeColors = hashMapOf(ERROR to 0x808080)\n        .puts(\n            CHAR_CONSTANT_HEAD,\n            CHAR_CONSTANT_TAIL,\n            CHAR_CONSTANT_ESCAPE,\n            STRING_LITERAL_HEAD,\n            STRING_LITERAL_TAIL,\n            STRING_LITERAL_ESCAPE,\n            0x808080\n        )\n        .puts(SLASH_SLASH, SLASH_ASTERISK, SLASH_ASTERISK___ASTERISK, SLASH_ASTERISK___ASTERISK_SLASH, 0x008000)\n        .puts(CHAR_CONSTANT_END, STRING_LITERAL_END, 0xdc009c)\n        .puts(NUMBER_HEAD, NUMBER_TAIL, 0x6400c8)\n        .puts(\n            START.read(\n                \"assert\", \"auto\", \"break\", \"case\", \"const\", \"continue\", \"default\", \"do\", \"else\",\n                \"enum\", \"extern\", \"for\", \"goto\", \"if\", \"register\", \"return\", \"sizeof\", \"static\", \"struct\", \"switch\",\n                \"typedef\", \"union\", \"volatile\", \"while\"\n            ), 0x0000ff\n        )\n        .puts(START.read(\"char\", \"double\", \"float\", \"int\", \"long\", \"short\", \"signed\", \"unsigned\", \"void\"), 0x008080)\n        .puts(START.read(\"(\", \")\", \"[\", \"]\", \"{\", \"}\"), 0xff0000)\n        .puts(\n            START.read(\n                \"!\", \"!=\", \"%\", \"%=\", \"&\", \"&&\", \"&=\", \"*\", \"*=\", \"+\", \"++\", \"+=\", \"-\", \"--\",\n                \"-=\", \"->\", \".\", \"/\", \"/=\", \":\", \"<\", \"<<\", \"<<=\", \"<=\", \"=\", \"==\", \">\", \">=\", \">>\", \">>=\", \"?\",\n                \"^\", \"^=\", \"|\", \"|=\", \"||\", \"~\"\n            ), 0x804040\n        )\n}\n"
  },
  {
    "path": "src/main/kotlin/ui/MainFrame.kt",
    "content": "package ui\n\nimport common.Diagnostic\nimport freditor.*\nimport interpreter.Interpreter\nimport interpreter.Memory\nimport semantic.Linter\nimport semantic.TypeChecker\nimport syntax.lexer.Lexer\nimport syntax.lexer.keywords\nimport syntax.parser.Parser\nimport syntax.parser.autocompleteIdentifier\nimport syntax.parser.translationUnit\nimport syntax.tree.*\nimport java.awt.BorderLayout\nimport java.awt.Dimension\nimport java.awt.EventQueue\nimport java.awt.Toolkit\nimport java.awt.event.KeyAdapter\nimport java.awt.event.KeyEvent\nimport java.util.concurrent.ArrayBlockingQueue\nimport java.util.function.Consumer\nimport javax.swing.*\nimport javax.swing.event.TreeModelListener\nimport javax.swing.tree.TreeModel\nimport javax.swing.tree.TreePath\n\nprivate val NAME = Regex(\"\"\"[A-Z_a-z][0-9A-Z_a-z]*\"\"\")\n\nobject StopTheProgram : Exception() {\n    private fun readResolve(): Any = StopTheProgram\n}\n\nfun <T : JComponent> T.sansSerif(): T {\n    this.font = Fronts.sansSerif\n    return this\n}\n\nclass MainFrame : JFrame() {\n    private val queue = ArrayBlockingQueue<String>(1)\n    private var interpreter = Interpreter(\"int main(){return 0;}\")\n\n    private val memoryUI = MemoryUI(Memory(emptySet(), emptyList()))\n    private val scrolledMemory = JScrollPane(memoryUI)\n    private val syntaxTree = JTree().sansSerif()\n    private val scrolledSyntaxTree = JScrollPane(syntaxTree)\n    private val visualizer = JTabbedPane().sansSerif()\n\n    private val tabbedEditors = TabbedEditors(\"skorbut\", Flexer, JavaIndenter.instance) { freditor ->\n        val editor = FreditorUI(freditor, 0, 25)\n\n        editor.addKeyListener(object : KeyAdapter() {\n            override fun keyPressed(event: KeyEvent) {\n                when (event.keyCode) {\n                    KeyEvent.VK_SPACE -> if (event.isControlDown) {\n                        autocompleteIdentifier()\n                    }\n\n                    KeyEvent.VK_R -> if (FreditorUI.isControlRespectivelyCommandDown(event) && event.isAltDown) {\n                        renameSymbol()\n                    }\n\n                    KeyEvent.VK_F1 -> showType()\n\n                    KeyEvent.VK_F3 -> jumpToDeclarationAndFindUsages()\n\n                    KeyEvent.VK_F5 -> into.doClick()\n                    KeyEvent.VK_F6 -> over.doClick()\n                    KeyEvent.VK_F7 -> r3turn.doClick()\n                }\n            }\n        })\n\n        editor.onRightClick = Consumer {\n            editor.clearDiagnostics()\n            showType()\n        }\n\n        editor\n    }\n\n    private val editor\n        get() = tabbedEditors.selectedEditor\n\n    private val slider = JSlider(0, 11, 0).sansSerif()\n    private val timer = Timer(1000) { queue.offer(\"into\") }\n\n    private val start = JButton(\"start\").sansSerif()\n    private val into = JButton(\"step into (F5)\").sansSerif()\n    private val over = JButton(\"step over (F6)\").sansSerif()\n    private val r3turn = JButton(\"step return (F7)\").sansSerif()\n    private val stop = JButton(\"stop\").sansSerif()\n    private val buttons = JPanel()\n\n    private val scrolledDiagnostics = JScrollPane()\n    private val consoleUI = JTextArea()\n    private val output = JTabbedPane().sansSerif()\n\n    private val controls = JPanel()\n\n    private var targetStackDepth = Int.MAX_VALUE\n    private var lastReceivedPosition = 0\n\n    init {\n        title = \"skorbut version ${Release.compilationDate(MainFrame::class.java)} @ ${editor.file.parent}\"\n\n        scrolledMemory.preferredSize = Dimension(500, 500)\n        scrolledSyntaxTree.preferredSize = Dimension(500, 500)\n\n        visualizer.addTab(\"memory\", scrolledMemory)\n        visualizer.addTab(\"syntax tree\", scrolledSyntaxTree)\n        visualizer.addChangeListener {\n            if (visualizer.selectedComponent === scrolledMemory) {\n                memoryUI.update()\n            } else {\n                hideDirtySyntaxTree()\n            }\n        }\n\n        if (editor.length() == 0) {\n            editor.load(helloWorld)\n        }\n        tabbedEditors.tabs.addChangeListener {\n            updateDiagnostics(emptyList())\n            hideDirtySyntaxTree()\n        }\n\n        val horizontalSplit = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, visualizer, tabbedEditors.tabs)\n        horizontalSplit.preferredSize = Dimension(1000, 500)\n\n        slider.majorTickSpacing = 1\n        slider.paintLabels = true\n\n        buttons.add(start)\n        into.isEnabled = false\n        buttons.add(into)\n        over.isEnabled = false\n        buttons.add(over)\n        r3turn.isEnabled = false\n        buttons.add(r3turn)\n        stop.isEnabled = false\n        buttons.add(stop)\n\n        val diagnosticsPanel = JPanel()\n        diagnosticsPanel.layout = BorderLayout()\n        diagnosticsPanel.add(scrolledDiagnostics)\n\n        consoleUI.font = Fronts.monospaced\n        consoleUI.isEditable = false\n\n        output.addTab(\"diagnostics\", scrolledDiagnostics)\n        output.addTab(\"console\", JScrollPane(consoleUI))\n        output.preferredSize = Dimension(0, Toolkit.getDefaultToolkit().screenSize.height / 5)\n\n        controls.layout = BoxLayout(controls, BoxLayout.Y_AXIS)\n        controls.add(slider)\n        controls.add(buttons)\n        controls.add(output)\n\n        val verticalSplit = JSplitPane(JSplitPane.VERTICAL_SPLIT, horizontalSplit, controls)\n        verticalSplit.resizeWeight = 1.0\n        add(verticalSplit)\n\n        listenToSyntaxTree()\n        listenToSlider()\n        listenToButtons()\n        listenToConsole()\n\n        defaultCloseOperation = EXIT_ON_CLOSE\n        tabbedEditors.saveOnExit(this)\n        pack()\n        isVisible = true\n        editor.requestFocusInWindow()\n    }\n\n    private fun hideDirtySyntaxTree() {\n        if (visualizer.selectedComponent === scrolledSyntaxTree) {\n            if (!isRunning() && !tryCompile()) {\n                visualizer.selectedComponent = scrolledMemory\n            }\n        }\n    }\n\n    private fun listenToSyntaxTree() {\n        syntaxTree.addTreeSelectionListener {\n            val node = it.newLeadSelectionPath?.lastPathComponent\n            if (node is Node) {\n                editor.setCursorTo(node.root().start)\n            }\n            editor.requestFocusInWindow()\n        }\n    }\n\n    private fun listenToConsole() {\n        consoleUI.addKeyListener(object : KeyAdapter() {\n            override fun keyTyped(event: KeyEvent) {\n                if (interpreter.console.isBlocked()) {\n                    interpreter.console.keyTyped(event.keyChar)\n                    updateConsole()\n                } else {\n                    JOptionPane.showMessageDialog(\n                        this@MainFrame,\n                        \"You probably forgot one STEP\",\n                        \"Nobody is waiting for input yet\",\n                        JOptionPane.ERROR_MESSAGE\n                    )\n                }\n            }\n        })\n    }\n\n    private fun updateConsole() {\n        consoleUI.text = interpreter.console.getText()\n        output.selectedIndex = 1\n        requestFocusInBlockedConsoleOrEditor()\n    }\n\n    private fun requestFocusInBlockedConsoleOrEditor() {\n        if (interpreter.console.isBlocked()) {\n            consoleUI.requestFocusInWindow()\n        } else {\n            editor.requestFocusInWindow()\n        }\n    }\n\n    private fun listenToSlider() {\n        slider.addChangeListener {\n            requestFocusInBlockedConsoleOrEditor()\n            configureTimer()\n        }\n    }\n\n    private fun configureTimer() {\n        val d = delay()\n        if (d < 0) {\n            timer.stop()\n        } else {\n            timer.initialDelay = d\n            timer.delay = d\n            if (isRunning()) {\n                timer.restart()\n            }\n        }\n    }\n\n    private fun delay(): Int {\n        val wait = slider.value\n        return if (wait == 0) -1 else 1.shl(slider.maximum - wait)\n    }\n\n    private fun isRunning(): Boolean = !start.isEnabled\n\n    private fun listenToButtons() {\n        start.addActionListener {\n            editor.indent()\n            editor.saveWithBackup()\n            editor.clearDiagnostics()\n            editor.requestFocusInWindow()\n            queue.clear()\n            if (tryCompile()) {\n                run()\n            }\n        }\n\n        into.addActionListener {\n            requestFocusInBlockedConsoleOrEditor()\n            queue.offer(\"into\")\n        }\n\n        over.addActionListener {\n            requestFocusInBlockedConsoleOrEditor()\n            queue.offer(\"over\")\n        }\n\n        r3turn.addActionListener {\n            requestFocusInBlockedConsoleOrEditor()\n            queue.offer(\"return\")\n        }\n\n        stop.addActionListener {\n            editor.requestFocusInWindow()\n            timer.stop()\n            queue.clear()\n            queue.put(\"stop\")\n            interpreter.console.stop()\n        }\n    }\n\n    private fun autocompleteIdentifier() {\n        try {\n            val suffixes = autocompleteIdentifier(editor.textBeforeSelection)\n            if (suffixes.size == 1) {\n                editor.insert(suffixes[0])\n            } else {\n                println(suffixes.sorted().joinToString(\", \"))\n            }\n        } catch (diagnostic: Diagnostic) {\n            showDiagnostic(diagnostic)\n            updateDiagnostics(arrayListOf(diagnostic))\n        }\n    }\n\n    private fun renameSymbol() {\n        if (isRunning() || !tryCompile()) return\n\n        val symbol = interpreter.typeChecker.symbolAt(editor.cursor()) ?: return\n\n        val oldName = symbol.name.text\n        val input = JOptionPane.showInputDialog(\n            this,\n            oldName,\n            \"rename symbol\",\n            JOptionPane.QUESTION_MESSAGE,\n            null,\n            null,\n            oldName\n        ) ?: return\n\n        val newName = input.toString().trim()\n        if (!NAME.matches(newName) || newName in keywords) return\n\n        val positions = IntArray(1 + symbol.usages.size)\n        positions[0] = symbol.name.start\n        symbol.usages.forEachIndexed { index, usage ->\n            positions[1 + index] = usage.name.start\n        }\n        editor.rename(oldName, newName, positions)\n        tryCompile()\n    }\n\n    private fun detectRoot(node: Node) {\n        val root = node.root()\n        if (editor.cursor() in root.start until root.end) {\n            root.error(\" $node \", -1)\n        }\n    }\n\n    private fun showType() {\n        try {\n            val translationUnit = Parser(Lexer(editor.text)).translationUnit()\n            TypeChecker(translationUnit)\n\n            translationUnit.walk({}) { node ->\n                if (node is Expression) {\n                    detectRoot(node)\n                } else if (node is FunctionDefinition) {\n                    detectRoot(node)\n                    node.parameters.forEach(::detectRoot)\n                } else if (node is NamedDeclarator) {\n                    detectRoot(node)\n                    if (node.declarator is Declarator.Initialized) {\n                        node.declarator.init.walk({}, ::detectRoot)\n                    }\n                }\n            }\n        } catch (diagnostic: Diagnostic) {\n            showDiagnostic(diagnostic)\n        }\n    }\n\n    private fun jumpToDeclarationAndFindUsages() {\n        if (isRunning() || !tryCompile()) return\n\n        val symbol = interpreter.typeChecker.symbolAt(editor.cursor()) ?: return\n\n        val symbolStart = symbol.name.start\n        editor.setCursorTo(symbolStart)\n\n        val name = symbol.name.text\n        val diagnostics = symbol.usages.map { usage ->\n            val usageStart = usage.name.start\n            val line = 1 + editor.lineOfPosition(usageStart)\n            Diagnostic(usageStart, \"usage of $name on line $line\", symbolStart)\n        }\n        updateDiagnostics(diagnostics)\n    }\n\n    private fun tryCompile(): Boolean {\n        try {\n            compile()\n            return true\n        } catch (diagnostic: Diagnostic) {\n            showDiagnostic(diagnostic)\n            updateDiagnostics(arrayListOf(diagnostic))\n        } catch (other: Throwable) {\n            showDiagnostic(other.message ?: \"null\")\n            other.printStackTrace()\n        }\n        return false\n    }\n\n    private fun compile() {\n        interpreter = Interpreter(editor.text)\n        updateSyntaxTreeModel()\n\n        val linter = Linter(interpreter.translationUnit)\n        updateDiagnostics(linter.getWarnings())\n    }\n\n    private fun run() {\n        interpreter.onMemorySet = { memory ->\n            EventQueue.invokeLater {\n                memoryUI.memory = memory\n            }\n        }\n        interpreter.before = ::pauseAt\n        interpreter.after = {\n            EventQueue.invokeAndWait {\n                if (visualizer.selectedComponent === scrolledMemory) {\n                    memoryUI.update()\n                }\n                if (interpreter.console.isDirty) {\n                    updateConsole()\n                }\n            }\n        }\n        consoleUI.text = \"\"\n        interpreter.console.update = { EventQueue.invokeAndWait(::updateConsole) }\n\n        tabbedEditors.tabs.isEnabled = false\n        start.isEnabled = false\n        into.isEnabled = true\n        over.isEnabled = true\n        r3turn.isEnabled = true\n        stop.isEnabled = true\n        configureTimer()\n        tryExecute()\n    }\n\n    private fun updateSyntaxTreeModel() {\n        syntaxTree.model = object : TreeModel {\n            override fun getRoot(): Any {\n                return interpreter.translationUnit\n            }\n\n            override fun getChildCount(parent: Any): Int {\n                var count = 0\n                (parent as Node).forEachChild { ++count }\n                return count\n            }\n\n            override fun getChild(parent: Any, index: Int): Any? {\n                var child: Node? = null\n                var i = 0\n                (parent as Node).forEachChild {\n                    if (i == index) {\n                        child = it\n                    }\n                    ++i\n                }\n                return child\n            }\n\n            override fun getIndexOfChild(parent: Any, child: Any): Int {\n                var index = -1\n                var i = 0\n                (parent as Node).forEachChild {\n                    if (it === child) {\n                        index = i\n                    }\n                    ++i\n                }\n                return index\n            }\n\n            override fun isLeaf(node: Any): Boolean {\n                return getChildCount(node) == 0\n            }\n\n            override fun addTreeModelListener(l: TreeModelListener?) {\n            }\n\n            override fun removeTreeModelListener(l: TreeModelListener?) {\n            }\n\n            override fun valueForPathChanged(path: TreePath?, newValue: Any?) {\n            }\n        }\n    }\n\n    private fun showDiagnostic(diagnostic: Diagnostic) {\n        editor.setCursorTo(diagnostic.position)\n        editor.requestFocusInWindow()\n        editor.showDiagnostic(diagnostic.message, diagnostic.position, diagnostic.columnDelta)\n    }\n\n    private fun showDiagnostic(position: Int, message: String) {\n        editor.setCursorTo(position)\n        editor.requestFocusInWindow()\n        editor.showDiagnostic(message)\n    }\n\n    private fun showDiagnostic(message: String) {\n        editor.requestFocusInWindow()\n        editor.showDiagnostic(message)\n    }\n\n    private fun updateDiagnostics(diagnostics: List<Diagnostic>) {\n        val list = JList(diagnostics.toTypedArray()).sansSerif()\n        list.addListSelectionListener { event ->\n            if (!event.valueIsAdjusting) {\n                val index = list.selectedIndex\n                if (index != -1) {\n                    val diagnostic = diagnostics[index]\n                    updateCaretPosition(diagnostic)\n                    editor.requestFocusInWindow()\n                    list.clearSelection()\n                }\n            }\n        }\n        scrolledDiagnostics.setViewportView(list)\n        if (diagnostics.isEmpty()) {\n            output.setTitleAt(0, \"diagnostics\")\n        } else {\n            output.setTitleAt(0, \"diagnostics (${diagnostics.size})\")\n            output.selectedIndex = 0\n        }\n    }\n\n    private fun updateCaretPosition(diagnostic: Diagnostic) {\n        if (editor.cursor() != diagnostic.position) {\n            editor.setCursorTo(diagnostic.position)\n        } else if (diagnostic.secondPosition != -1) {\n            editor.setCursorTo(diagnostic.secondPosition)\n        }\n    }\n\n    private fun pauseAt(position: Int) {\n        lastReceivedPosition = position\n        val entry = if (interpreter.stackDepth <= targetStackDepth) {\n            // Step into mode\n            EventQueue.invokeLater {\n                editor.setCursorTo(position)\n            }\n            // Block until the next button press\n            queue.take()\n        } else {\n            // Step over/return mode\n            // Don't block, but consume potential button presses, especially stop\n            queue.poll()\n        }\n        when (entry) {\n            \"into\" -> {\n                targetStackDepth = Int.MAX_VALUE\n            }\n\n            \"over\" -> {\n                targetStackDepth = interpreter.stackDepth\n            }\n\n            \"return\" -> {\n                targetStackDepth = interpreter.stackDepth - 1\n            }\n\n            \"stop\" -> {\n                timer.stop()\n                throw StopTheProgram\n            }\n        }\n    }\n\n    private fun tryExecute() {\n        Thread {\n            try {\n                targetStackDepth = Int.MAX_VALUE\n                lastReceivedPosition = 0\n                interpreter.run(editor.cursor(), editor.length())\n            } catch (_: StopTheProgram) {\n            } catch (diagnostic: Diagnostic) {\n                EventQueue.invokeLater {\n                    showDiagnostic(diagnostic)\n                }\n            } catch (other: Throwable) {\n                EventQueue.invokeLater {\n                    showDiagnostic(lastReceivedPosition, other.message ?: \"null\")\n                    other.printStackTrace()\n                }\n            } finally {\n                EventQueue.invokeLater {\n                    tabbedEditors.tabs.isEnabled = true\n                    start.isEnabled = true\n                    into.isEnabled = false\n                    over.isEnabled = false\n                    r3turn.isEnabled = false\n                    stop.isEnabled = false\n                    timer.stop()\n                }\n            }\n        }.start()\n    }\n}\n\nconst val helloWorld = \"\"\"void demo()\n{\n    char a[] = \"hi\";\n    char * p = a;\n    ++p;\n    ++p;\n    ++p;\n}\n\"\"\"\n"
  },
  {
    "path": "src/main/kotlin/ui/MemoryUI.kt",
    "content": "package ui\n\nimport common.Counter\nimport freditor.Fronts\nimport interpreter.Memory\nimport interpreter.PointerValue\nimport interpreter.Segment\nimport semantic.types.ArrayType\nimport semantic.types.StructType\nimport semantic.types.Type\n\nimport java.awt.*\nimport java.awt.geom.Line2D\nimport java.awt.geom.QuadCurve2D\n\nimport javax.swing.*\nimport javax.swing.border.CompoundBorder\nimport javax.swing.border.EmptyBorder\nimport javax.swing.border.LineBorder\nimport javax.swing.border.TitledBorder\nimport kotlin.math.pow\nimport kotlin.math.sqrt\n\nclass MemoryUI(var memory: Memory) : JPanel() {\n    init {\n        layout = BoxLayout(this, BoxLayout.Y_AXIS)\n    }\n\n    private val emptyBorder = EmptyBorder(8, 8, 8, 8)\n    private val stringsBorder = LineBorder(Color.LIGHT_GRAY, 2, true)\n    private val staticsBorder = LineBorder(Color.GRAY, 2, true)\n    private val stackBorder = LineBorder(Color.BLUE, 2, true)\n    private val heapBorder = LineBorder(Color(128, 0, 128), 2, true)\n    private var lineBorder = stringsBorder\n    private val rigidWidth = Dimension(300, 0)\n\n    private fun Segment.objectComponent(title: String, qualified: Type): JComponent {\n        val type = qualified.unqualified()\n        val address = valueIndex\n        val component = when (type) {\n            is ArrayType -> arrayComponent(type)\n            is StructType -> structComponent(type)\n            else -> scalarComponent()\n        }\n        component.alignmentX = Component.LEFT_ALIGNMENT\n        component.border = CompoundBorder(\n            emptyBorder,\n            TitledBorder(lineBorder, title, TitledBorder.LEADING, TitledBorder.DEFAULT_POSITION, Fronts.sansSerif)\n        )\n        objects[this]!![address][type] = component\n        return component\n    }\n\n    private fun Segment.arrayComponent(type: ArrayType): JComponent {\n        val cells = JPanel()\n        val axis = if (type.dimensions().and(1) == 1) BoxLayout.X_AXIS else BoxLayout.Y_AXIS\n        cells.layout = BoxLayout(cells, axis)\n        for (i in 0 until type.size) {\n            cells.add(objectComponent(i.toString(), type.elementType))\n        }\n        return cells\n    }\n\n    private fun Segment.structComponent(type: StructType): JComponent {\n        val cells = JPanel()\n        val axis = BoxLayout.Y_AXIS\n        cells.layout = BoxLayout(cells, axis)\n        for (symbol in type.members) {\n            val name = symbol.name.text\n            if (!name.startsWith('_')) {\n                cells.add(objectComponent(name, symbol.type))\n            } else {\n                valueIndex += symbol.type.count()\n            }\n        }\n        return cells\n    }\n\n    private fun Segment.scalarComponent(): JComponent {\n        val value = this[valueIndex++]\n        val scalar = JLabel(\" %3s \".format(value.show()))\n        scalar.font = Fronts.monospaced\n        if (value is PointerValue && value.referenced.isReferable()) {\n            pointers[scalar] = value\n        }\n        return scalar\n    }\n\n    private val objects = HashMap<Segment, MutableList<HashMap<Type, JComponent>>>()\n    private val pointers = LinkedHashMap<JComponent, PointerValue>()\n    private var valueIndex = 0\n\n    fun update() {\n        removeAll()\n        objects.clear()\n        pointers.clear()\n        updateSingleSegment(memory.stringConstants, stringsBorder)\n        updateSingleSegment(memory.staticVariables, staticsBorder)\n        updateMultipleSegments(memory.heap, heapBorder)\n        add(Box.createVerticalGlue())\n        updateMultipleSegments(memory.stack, stackBorder)\n        revalidate()\n        repaint()\n    }\n\n    private fun updateSingleSegment(segment: Segment, border: LineBorder) {\n        val structType = segment.type as StructType\n        if (structType.members.isNotEmpty()) {\n            lineBorder = border\n            update(segment)\n        }\n    }\n\n    private fun update(segment: Segment) {\n        objects[segment] = MutableList(segment.type.count()) { HashMap() }\n        valueIndex = 0\n        with(segment) {\n            if (type is StructType) {\n                val title = \"%04x  %s\".format(address.and(0xffff), type.name.text)\n                val component = objectComponent(title, type)\n                val rigidArea = Box.createRigidArea(rigidWidth) as JComponent\n                rigidArea.alignmentX = JComponent.LEFT_ALIGNMENT\n                component.add(rigidArea)\n                add(component)\n            } else {\n                val title = \"%04x\".format(address.and(0xffff))\n                add(objectComponent(title, type))\n            }\n        }\n    }\n\n    private fun updateMultipleSegments(segments: List<Segment>, border: LineBorder) {\n        lineBorder = border\n        segments.asReversed().forEach(::update)\n    }\n\n    override fun paint(graphics: Graphics) {\n        super.paint(graphics)\n        val g2d = graphics as Graphics2D\n        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)\n        g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE)\n        g2d.stroke = stroke\n        g2d.color = color\n        val pointerCounter = Counter()\n        for ((source, pointer) in pointers.entries) {\n            val place = pointerCounter.count(pointer)\n            val obj = pointer.referenced\n            val offset = if (obj.isSentinel()) obj.minus(1).offset else obj.offset\n            objects[obj.segment]!![offset][obj.type.unqualified()]?.let { target ->\n                val sourcePos = SwingUtilities.convertPoint(source, 0, 0, this)\n                val targetPos = SwingUtilities.convertPoint(target, 0, 0, this)\n                val x1 = sourcePos.x + source.width / 2\n                val y1 = sourcePos.y + source.height / 2\n                val x2 = targetPos.x + if (obj.isSentinel()) target.width else lerp(source.width, 0.5.pow(place * 0.5), 16)\n                var y2 = targetPos.y + 8\n                if (y2 < y1) {\n                    y2 = targetPos.y + target.height - 8\n                }\n                drawPointer(g2d, x1.toDouble(), y1.toDouble(), x2.toDouble(), y2.toDouble())\n            }\n        }\n    }\n\n    private fun lerp(zero: Int, x: Double, one: Int): Int = (zero.toDouble() * (1 - x) + one.toDouble() * x).toInt()\n\n    private fun drawPointer(g2d: Graphics2D, x1: Double, y1: Double, x2: Double, y2: Double) {\n        var deltaX = x2 - x1\n        var deltaY = y2 - y1\n        if (deltaY > 0) {\n            deltaX = -deltaX\n            deltaY = -deltaY\n        }\n        val controlX = (x1 + x2 - deltaY) * 0.5\n        val controlY = (y1 + y2 + deltaX) * 0.5\n        g2d.draw(QuadCurve2D.Double(x1, y1, controlX, controlY, x2, y2))\n\n        deltaX = controlX - x2\n        deltaY = controlY - y2\n        val scaleFactor = 8.0 / sqrt((deltaX * deltaX + deltaY * deltaY) * 2)\n        deltaX *= scaleFactor\n        deltaY *= scaleFactor\n        g2d.draw(Line2D.Double(x2, y2, x2 + (deltaX - deltaY), y2 + (deltaY + deltaX)))\n        g2d.draw(Line2D.Double(x2, y2, x2 + (deltaX + deltaY), y2 + (deltaY - deltaX)))\n    }\n\n    private val stroke = BasicStroke(2f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)\n    private val color = Color(1.0f, 0.5f, 0f, 0.75f)\n}\n"
  },
  {
    "path": "src/test/kotlin/interpreter/InterpreterTest.kt",
    "content": "package interpreter\n\nimport org.junit.jupiter.api.Test\n\nclass InterpreterTest {\n    private fun run(program: String) {\n        Interpreter(program).run(program.length, program.length)\n    }\n\n    @Test\n    fun sum() {\n        run(\n            \"\"\"\nint sum(int a, int b)\n{\n    return a + b;\n}\n\nint main()\n{\n    assert sum(1, 2) == 3;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun fak() {\n        run(\n            \"\"\"\nint fak(int n)\n{\n    int result;\n    if (n == 0)\n    {\n        result = 1;\n    }\n    else\n    {\n        result = fak(n - 1);\n        result = n * result;\n    }\n    return result;\n}\n\nint main()\n{\n    assert fak(5) == 120;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun passingStrategies() {\n        run(\n            \"\"\"\nint pass(int i, int * p)\n{\n    i = 3;\n    *p = 4;\n    return i;\n}\n\nint main()\n{\n    int a = 1;\n    int b = 2;\n    int c = pass(a, &b);\n    assert a == 1;\n    assert b == 4;\n    assert c == 3;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun doubleResultType() {\n        run(\n            \"\"\"\ndouble the_answer()\n{\n    return 42.5;\n}\n\nint main()\n{\n    assert the_answer() == 42.5;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun voidReturnType() {\n        run(\n            \"\"\"\nvoid swap(int * p, int * q)\n{\n    int c = *p;\n    *p = *q;\n    *q = c;\n}\n\nint main()\n{\n    int i = 1;\n    int k = 2;\n    swap(&i, &k);\n    assert i == 2;\n    assert k == 1;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun multiDeclaration() {\n        run(\n            \"\"\"\nint main()\n{\n    int *a, b, **c;\n    a = &b;\n    c = &a;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun arrayAccess() {\n        run(\n            \"\"\"\nint main()\n{\n    int a[2][3];\n    a[0][0] = 2;\n    a[0][1] = 3;\n    a[0][2] = 5;\n    a[1][0] = 7;\n    a[1][1] = 11;\n    a[1][2] = 13;\n\n    assert a[0][0] == 2;\n    assert a[0][1] == 3;\n    assert a[0][2] == 5;\n    assert a[1][0] == 7;\n    assert a[1][1] == 11;\n    assert a[1][2] == 13;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun decay1D() {\n        run(\n            \"\"\"\nint main()\n{\n    int a[2][3];\n    a[1][2] = 42;\n    int * p = a[1];\n    assert p[2] == 42;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun decay2D() {\n        run(\n            \"\"\"\nint main()\n{\n    int a[2][3];\n    a[1][2] = 42;\n    int (*p)[3] = a;\n    assert p[1][2] == 42;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun pointerArithmetic() {\n        run(\n            \"\"\"\nint main()\n{\n    int a[9];\n    int * p = a + 2;\n    int * q = &a[9] - 4;\n    assert q - p == 3;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun charConstants() {\n        run(\n            \"\"\"\nint main()\n{\n    char a = 'a';\n    assert 'z' - a == 25;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun latin1() {\n        run(\n            \"\"\"\nint main()\n{\n    char x = 'ß';\n    int i = x;\n    assert x == -33;\n    assert i == -33;\n\n    char a[] = \"äöüÄÖÜß\";\n    assert a[0] == -28;\n    assert a[1] == -10;\n    assert a[2] == -4;\n    assert a[3] == -60;\n    assert a[4] == -42;\n    assert a[5] == -36;\n    assert a[6] == -33;\n    \n    char * s = \"äöüÄÖÜß\";\n    assert s[0] == -28;\n    assert s[1] == -10;\n    assert s[2] == -4;\n    assert s[3] == -60;\n    assert s[4] == -42;\n    assert s[5] == -36;\n    assert s[6] == -33;\n    \n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun sumOfFirstTenNumbers() {\n        run(\n            \"\"\"\nint main()\n{\n    int sum = 0;\n    for (int i = 1; i <= 10; ++i)\n    {\n        sum = sum + i;\n    }\n    assert sum == 55;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun forIntInt() {\n        run(\n            \"\"\"\nint main()\n{\n    int sum = 0;\n    for (int a = 1, b = 9; a <= b; ++a, --b)\n    {\n        sum += a * b;\n    }\n    assert sum == 1*9 + 2*8 + 3*7 + 4*6 + 5*5;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun forIntChar() {\n        run(\n            \"\"\"\nint main()\n{\n    char a[7];\n    for (struct {int i; char c;} x = {0, 'A'}; x.i < sizeof a; ++x.i, ++x.c)\n    {\n        a[x.i] = x.c;\n    }\n    assert a[0] == 'A';\n    assert a[1] == 'B';\n    assert a[2] == 'C';\n    assert a[3] == 'D';\n    assert a[4] == 'E';\n    assert a[5] == 'F';\n    assert a[6] == 'G';\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun forStatic() {\n        run(\n            \"\"\"\nvoid fill(char * p, char * q) {\n    for (static char c = 'A'; p < q; ++p) {\n        *p = c++;\n    }\n}\n\nint main()\n{\n    char a[7];\n    fill(a + 0, a + 1);\n    fill(a + 1, a + 3);\n    fill(a + 3, a + 7);\n\n    assert a[0] == 'A';\n    assert a[1] == 'B';\n    assert a[2] == 'C';\n    assert a[3] == 'D';\n    assert a[4] == 'E';\n    assert a[5] == 'F';\n    assert a[6] == 'G';\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun forTypedef() {\n        run(\n            \"\"\"\nint main()\n{\n    char a[5];\n    int i = 0;\n    for (typedef const char * str; i < sizeof a; ++i) {\n        str p = \"world\" + i;\n        a[i] = *p;\n    }\n    assert a[0] == 'w';\n    assert a[1] == 'o';\n    assert a[2] == 'r';\n    assert a[3] == 'l';\n    assert a[4] == 'd';\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun forScopes() {\n        run(\n            \"\"\"\nint main()\n{\n    int i = 1;\n    assert i == 1;\n    for (int i = 2; ; ) {\n        assert i == 2;\n\n        int i = 3;\n        assert i == 3;\n\n        break;\n    }\n    assert i == 1;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun gcd() {\n        run(\n            \"\"\"int gcd(int x, int y)\n{\n    while (y)\n    {\n        int z = x % y;\n        x = y;\n        y = z;\n    }\n    return x;\n}\n\nint main()\n{\n    assert gcd(100, 24) == 4;\n    assert gcd(90, 120) == 30;\n    assert gcd(13, 99) == 1;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun twoDimensionalPrimes() {\n        run(\n            \"\"\"\nint main()\n{\n    int primes[2][4] = {{2, 3, 5, 7}, {11, 13, 17, 19}};\n    assert primes[0][0] == 2;\n    assert primes[0][1] == 3;\n    assert primes[0][2] == 5;\n    assert primes[0][3] == 7;\n    assert primes[1][0] == 11;\n    assert primes[1][1] == 13;\n    assert primes[1][2] == 17;\n    assert primes[1][3] == 19;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun incompleteArrayParameter() {\n        run(\n            \"\"\"\nint sum(int a[], int n)\n{\n    int s = 0;\n    int i;\n    for (i = 0; i < n; ++i)\n    {\n        s = s + a[i];\n    }\n    return s;\n}\n\nint main()\n{\n    int primes[] = {2, 3, 5, 7, 11, 13, 17, 19};\n    assert sum(primes, 8) == 77;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun bogusSizeArrayParameter() {\n        run(\n            \"\"\"\nint sum(int a[5], int n)\n{\n    int sum = 0;\n    int i;\n    for (i = 0; i < n; ++i)\n    {\n        sum = sum + a[i];\n    }\n    return sum;\n}\n\nint main()\n{\n    int primes[] = {2, 3, 5, 7, 11, 13, 17, 19};\n    assert sum(primes, 8) == 77;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun pointerIncrement() {\n        run(\n            \"\"\"\nint main()\n{\n    char * a = \"123\";\n    char * b = a++;\n    char * c = ++a;\n    assert *a == '3';\n    assert *b == '1';\n    assert *c == '3';\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun pointerDecrement() {\n        run(\n            \"\"\"\nint main()\n{\n    char * a = \"123\" + 2;\n    char * b = a--;\n    char * c = --a;\n    assert *a == '1';\n    assert *b == '3';\n    assert *c == '1';\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun relationalAndEqualityOnPointers() {\n        run(\n            \"\"\"\nint main()\n{\n    char * a = \"hello\";\n    char * b = a;\n    assert a == b;\n    assert a <= b;\n    assert b >= a;\n    ++b;\n    assert a != b;\n    assert a < b;\n    assert a <= b;\n    assert b > a;\n    assert b >= a;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun sizeof() {\n        run(\n            \"\"\"\nint main()\n{\n    char c;\n    assert sizeof c == 1;\n    int i;\n    assert sizeof i == 4;\n    unsigned u;\n    assert sizeof u == 4;\n    float f;\n    assert sizeof f == 4;\n    double d;\n    assert sizeof d == 8;\n    int a[6];\n    assert sizeof a == 24;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun sizeofType() {\n        run(\n            \"\"\"\nint main()\n{\n    assert sizeof(char) == 1;\n    assert sizeof(int) == 4;\n    assert sizeof(unsigned) == 4;\n    assert sizeof(float) == 4;\n    assert sizeof(double) == 8;\n    assert sizeof(int[6]) == 24;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun selfReferentialDeclaration() {\n        run(\n            \"\"\"\nint main()\n{\n    char x;\n    {\n        int x = sizeof x;\n        assert x == sizeof x;\n    }\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun sizeOfParen() {\n        run(\n            \"\"\"\nint main()\n{\n    assert sizeof(\"hello\" + 2)[3] == 1;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun parenthesizedExpression() {\n        run(\n            \"\"\"\nint main()\n{\n    assert 1 + 2 * 3 + 4 == 11;\n    assert (1 + 2) * (3 + 4) == 21;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun comma() {\n        run(\n            \"\"\"\nint main()\n{\n    int a;\n    int b;\n    int c;\n    assert (a = 2, b = 3, c = 5) == 5;\n    assert a == 2;\n    assert b == 3;\n    assert c == 5;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun logicalNot() {\n        run(\n            \"\"\"\nint main()\n{\n    assert !0 == 1;\n    assert !1 == 0;\n    assert !2 == 0;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun logicalAnd() {\n        run(\n            \"\"\"\nint main()\n{\n    assert (0 && 0) == 0;\n    assert (0 && 1) == 0;\n    assert (1 && 0) == 0;\n    assert (1 && 1) == 1;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun logicalOr() {\n        run(\n            \"\"\"\nint main()\n{\n    assert (0 || 0) == 0;\n    assert (0 || 1) == 1;\n    assert (1 || 0) == 1;\n    assert (1 || 1) == 1;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun voidPointers() {\n        run(\n            \"\"\"\nint main()\n{\n    int x;\n    int * a = &x;\n    void * b = a;\n    int * c = b;\n    assert a == b;\n    assert b == c;\n    assert a == c;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun plusMinusAssignment() {\n        run(\n            \"\"\"\nint main()\n{\n    int sum = 0;\n    int i;\n    for (i = 9; i >= 0; i -= 2)\n    {\n        sum += i;\n    }\n    assert sum == 9 + 7 + 5 + 3 + 1;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun plusAssignmentConst() {\n        run(\n            \"\"\"\nint main()\n{\n    int a = 1;\n    const int b = 2;\n    a += b; // failed to typecheck\n    assert(a == 3);\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun bitwiseAnd() {\n        run(\n            \"\"\"\nint main()\n{\n    assert (1103341801 & 630371112) == 25337896;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun bitwiseXor() {\n        run(\n            \"\"\"\nint main()\n{\n    assert (1103341801 ^ 630371112) == 1683037121;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun bitwiseOr() {\n        run(\n            \"\"\"\nint main()\n{\n    assert (1103341801 | 630371112) == 1708375017;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun doWhile() {\n        run(\n            \"\"\"\nint main()\n{\n    int i = 8;\n    do\n    {\n        ++i;\n    } while (i & (i - 1));\n    assert i == 16;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun functionReturningPointerToArray() {\n        run(\n            \"\"\"\nchar (*f())[6]\n{\n    return &\"hello\";\n}\n\nint main()\n{\n    char (*p)[6] = f();\n    assert p[0][0] == 'h';\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun rand() {\n        run(\n            \"\"\"\nunsigned random;\n\nvoid srand(unsigned seed)\n{\n    random = seed;\n}\n\nint rand()\n{\n    random = random * 214013 + 2531011;\n    return random * 2 / 131072;\n}\n\nint main()\n{\n    srand(0);\n    assert rand() == 38;\n    assert rand() == 7719;\n    assert rand() == 21238;\n    assert rand() == 2437;\n    assert rand() == 8855;\n    assert rand() == 11797;\n    assert rand() == 8365;\n    assert rand() == 32285;\n    assert rand() == 10450;\n    assert rand() == 30612;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun functionPrototype() {\n        run(\n            \"\"\"\nint square(int x);\n\nint main()\n{\n    assert square(9) == 81;\n    return 0;\n}\n\nint square(int x)\n{\n    return x * x;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun passStructByReference() {\n        run(\n            \"\"\"\nstruct Point\n{\n    int x, y;\n    int z;\n};\n\nvoid add(struct Point * a, struct Point * b, struct Point * s)\n{\n    s->x = a->x + b->x;\n    s->y = a->y + b->y;\n    s->z = a->z + b->z;\n}\n\nint main()\n{\n    struct Point p = {2, 3, 5};\n    struct Point q = {7, 11, 13};\n    struct Point r;\n    add(&p, &q, &r);\n    assert r.x == 9;\n    assert r.y == 14;\n    assert r.z == 18;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun passStructByValue() {\n        run(\n            \"\"\"\nstruct Point\n{\n    int x;\n    int y, z;\n};\n\nvoid add(struct Point * dst, struct Point src)\n{\n    dst->x += src.x;\n    dst->y += src.y;\n    dst->z += src.z;\n    // modifying src should have no effect\n    ++src.x;\n    ++src.y;\n    ++src.z;\n}\n\nint main()\n{\n    struct Point a = {2, 3, 5};\n    struct Point b = {7, 11, 13};\n\n    add(&a, b);\n\n    assert a.x == 9;\n    assert a.y == 14;\n    assert a.z == 18;\n\n    assert b.x == 7;\n    assert b.y == 11;\n    assert b.z == 13;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun assignStruct() {\n        run(\n            \"\"\"\nstruct Point\n{\n    int x, y, z;\n};\n\nint main()\n{\n    struct Point a = {2, 3, 5};\n    const struct Point b = a;\n    struct Point c;\n    c = b;\n\n    assert a.x == 2;\n    assert a.y == 3;\n    assert a.z == 5;\n\n    assert b.x == 2;\n    assert b.y == 3;\n    assert b.z == 5;\n\n    assert c.x == 2;\n    assert c.y == 3;\n    assert c.z == 5;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun initializeStructInArray() {\n        run(\n            \"\"\"\nstruct Point\n{\n    int x, y, z;\n};\n\nint main()\n{\n    const struct Point b = {7, 11, 13};\n    struct Point d = {29, 31, 37};\n    const struct Point a[] = {{2, 3, 5}, b, {17, 19, 23}, d};\n\n    assert a[0].x == 2;\n    assert a[0].y == 3;\n    assert a[0].z == 5;\n\n    assert a[1].x == 7;\n    assert a[1].y == 11;\n    assert a[1].z == 13;\n\n    assert a[2].x == 17;\n    assert a[2].y == 19;\n    assert a[2].z == 23;\n\n    assert a[3].x == 29;\n    assert a[3].y == 31;\n    assert a[3].z == 37;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun passFunctionPointer() {\n        run(\n            \"\"\"\nint twice(int (*f)(int x), int x)\n{\n    return f(f(x));\n}\n\nint square(int x)\n{\n    return x * x;\n}\n\nint main()\n{\n    assert twice(square, 3) == 81;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun indirectMemberAccessViaArray() {\n        run(\n            \"\"\"\nint main()\n{\n    struct Point { int x, y; } a[1];\n    a->x = 1;\n    a->y = 2;\n    assert a[0].x == 1;\n    assert a[0].y == 2;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun unaryPlus() {\n        run(\n            \"\"\"\nint abs(int x)\n{\n    if (x < 0) return -x; else return +x;\n}\n\nint main()\n{\n    assert abs(+42) == 42;\n    assert abs(-42) == 42;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun conditionalArithmetic() {\n        run(\n            \"\"\"\nint abs(int x)\n{\n    return (x < 0) ? -x : +x;\n}\n\nint main()\n{\n    assert abs(+42) == 42;\n    assert abs(-42) == 42;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun conditionalMixedArithmetic() {\n        run(\n            \"\"\"\nint main()\n{\n    double lossy = 1 ? 1234567890 : 3.14f;\n    assert lossy == 1234567936;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun conditionalVoid() {\n        run(\n            \"\"\"\nchar x;\n\nvoid True()\n{\n    x = 't';\n}\n\nvoid False()\n{\n    x = 'f';\n}\n\nint main()\n{\n    0 ? True() : False();\n    assert x == 'f';\n    1 ? True() : False();\n    assert x == 't';\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun conditionalPointers() {\n        run(\n            \"\"\"\nint * minimum(int * p, int * q)\n{\n    return (*q < *p) ? q : p;\n}\n\nint main()\n{\n    int a[] = {2, 3};\n    *minimum(a, a + 1) = 5;\n    *minimum(a, a + 1) = 7;\n    assert a[0] == 5;\n    assert a[1] == 7;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun conditionalVoidPointers() {\n        run(\n            \"\"\"\nint main()\n{\n    int * a = malloc(sizeof(int));\n    void * p = a;\n    int * b = malloc(sizeof(int));\n    void * q = b;\n    free(1 ? p : q);\n    free(0 ? p : q);\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun conditionalMixedVoidPointers1() {\n        run(\n            \"\"\"\nint main()\n{\n    int * a = malloc(sizeof(int));\n    void * p = a;\n    int * q = malloc(sizeof(int));\n    free(1 ? p : q);\n    free(0 ? p : q);\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun conditionalMixedVoidPointers2() {\n        run(\n            \"\"\"\nint main()\n{\n    int * p = malloc(sizeof(int));\n    int * b = malloc(sizeof(int));\n    void * q = b;\n    free(1 ? p : q);\n    free(0 ? p : q);\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun conditionalChained() {\n        run(\n            \"\"\"\nint signum(int x)\n{\n    return x < 0 ? -1 : x > 0 ? +1 : +-0;\n}\n\nint main()\n{\n    assert signum(-42) == -1;\n    assert signum(000) == 00;\n    assert signum(+42) == +1;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun forOptional1() {\n        run(\n            \"\"\"\nint main()\n{\n    int sum = 0;\n    int i;\n    for (i = 1; i <= 10; )\n    {\n        sum += i;\n        ++i;\n    }\n    assert sum == 55;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun forOptional2() {\n        run(\n            \"\"\"\nint main()\n{\n    int sum = 0;\n    int i;\n    for (i = 1; ; ++i)\n    {\n        if (!(i <= 10))\n        {\n            assert sum == 55;\n            return 0;\n        }\n        sum += i;\n    }\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun forOptional3() {\n        run(\n            \"\"\"\nint main()\n{\n    int sum = 0;\n    int i;\n    for (i = 1; ; )\n    {\n        if (!(i <= 10))\n        {\n            assert sum == 55;\n            return 0;\n        }\n        sum += i;\n        ++i;\n    }\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun forOptional4() {\n        run(\n            \"\"\"\nint main()\n{\n    int sum = 0;\n    int i = 1;\n    for (; i <= 10; ++i)\n    {\n        sum += i;\n    }\n    assert sum == 55;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun forOptional5() {\n        run(\n            \"\"\"\nint main()\n{\n    int sum = 0;\n    int i = 1;\n    for (; i <= 10; )\n    {\n        sum += i;\n        ++i;\n    }\n    assert sum == 55;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun forOptional6() {\n        run(\n            \"\"\"\nint main()\n{\n    int sum = 0;\n    int i = 1;\n    for (; ; ++i)\n    {\n        if (!(i <= 10))\n        {\n            assert sum == 55;\n            return 0;\n        }\n        sum += i;\n    }\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun forOptional7() {\n        run(\n            \"\"\"\nint main()\n{\n    int sum = 0;\n    int i = 1;\n    for (; ; )\n    {\n        if (!(i <= 10))\n        {\n            assert sum == 55;\n            return 0;\n        }\n        sum += i;\n        ++i;\n    }\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun mallocSingleElement() {\n        run(\n            \"\"\"\nint main()\n{\n    int * p = malloc(4);\n    *p = 42;\n    free(p);\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun mallocArray() {\n        run(\n            \"\"\"\nint main()\n{\n    int * p = malloc(12);\n    p[0] = 2;\n    p[1] = 3;\n    p[2] = 5;\n    free(p);\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun passMallocResultToFunction() {\n        run(\n            \"\"\"\nint * foo(int * p)\n{\n    *p = 42;\n    return p;\n}\n\nint main()\n{\n    free(foo(malloc(4)));\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun typedefScopes() {\n        run(\n            \"\"\"\ntypedef int X;\n\nX main()\n{\n    X a = 42;\n    {\n        X Y = 3;\n        X X = 2;\n        X * Y;\n    }\n    X * Y;\n    Y = &a;\n    char typedef X;\n    X * Z;\n    Z = \"hello\";\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun staticLocalCounter() {\n        run(\n            \"\"\"\nint a;\n\nint id()\n{\n    int b;\n    static int counter = 0;\n    int c;\n    return counter++;\n}\n\nint d;\n\nint main()\n{\n    int e;\n    assert id() == 0;\n    assert id() == 1;\n    assert id() == 2;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun staticLocalStringArray() {\n        run(\n            \"\"\"\nchar * weekday(int n)\n{\n    static char * table[] = {\n        \"Sunday\",\n        \"Monday\",\n        \"Tuesday\",\n        \"Wednesday\",\n        \"Thursday\",\n        \"Friday\",\n        \"Saturday\"\n    };\n    return table[n];\n}\n\nint main()\n{\n    assert weekday(0) == \"Sunday\";\n    assert weekday(6) == \"Saturday\";\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun layoutForStaticArrayWithDeducedSize() {\n        run(\n            \"\"\"\nint a[] = {1, 2, 3};\nint x = 4;\n\nint main()\n{\n    assert a[0] == 1;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun signedCharDeclarations() {\n        run(\n            \"\"\"\nint main()\n{\n    signed char a = -1;\n    assert a < 0;\n    assert sizeof(a) == 1;\n\n    char signed b = -1;\n    assert b < 0;\n    assert sizeof(b) == 1;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun unsignedCharDeclarations() {\n        run(\n            \"\"\"\nint main()\n{\n    unsigned char a = -1;\n    assert a > 0;\n    assert sizeof(a) == 1;\n\n    char unsigned b = -1;\n    assert b > 0;\n    assert sizeof(b) == 1;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun signedShortDeclarations() {\n        run(\n            \"\"\"\nint main()\n{\n    short a = -1;\n    assert a < 0;\n    assert sizeof(a) == 2;\n\n\n    short int b = -1;\n    assert b < 0;\n    assert sizeof(b) == 2;\n\n    int short c = -1;\n    assert c < 0;\n    assert sizeof(c) == 2;\n\n\n    signed short d = -1;\n    assert d < 0;\n    assert sizeof(d) == 2;\n\n    short signed e = -1;\n    assert e < 0;\n    assert sizeof(e) == 2;\n\n\n    signed short int f = -1;\n    assert f < 0;\n    assert sizeof(f) == 2;\n\n    signed int short g = -1;\n    assert g < 0;\n    assert sizeof(g) == 2;\n\n    short signed int h = -1;\n    assert h < 0;\n    assert sizeof(h) == 2;\n\n    short int signed i = -1;\n    assert i < 0;\n    assert sizeof(i) == 2;\n\n    int signed short j = -1;\n    assert j < 0;\n    assert sizeof(j) == 2;\n\n    int short signed k = -1;\n    assert k < 0;\n    assert sizeof(k) == 2;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun unsignedShortDeclarations() {\n        run(\n            \"\"\"\nint main()\n{\n    unsigned short d = -1;\n    assert d > 0;\n    assert sizeof(d) == 2;\n\n    short unsigned e = -1;\n    assert e > 0;\n    assert sizeof(e) == 2;\n\n\n    unsigned short int f = -1;\n    assert f > 0;\n    assert sizeof(f) == 2;\n\n    unsigned int short g = -1;\n    assert g > 0;\n    assert sizeof(g) == 2;\n\n    short unsigned int h = -1;\n    assert h > 0;\n    assert sizeof(h) == 2;\n\n    short int unsigned i = -1;\n    assert i > 0;\n    assert sizeof(i) == 2;\n\n    int unsigned short j = -1;\n    assert j > 0;\n    assert sizeof(j) == 2;\n\n    int short unsigned k = -1;\n    assert k > 0;\n    assert sizeof(k) == 2;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun signedIntDeclarations() {\n        run(\n            \"\"\"\nint main()\n{\n    int a = -1;\n    assert a < 0;\n    assert sizeof(a) == 4;\n\n    signed b = -1;\n    assert b < 0;\n    assert sizeof(b) == 4;\n\n\n    signed int d = -1;\n    assert d < 0;\n    assert sizeof(d) == 4;\n\n    int signed e = -1;\n    assert e < 0;\n    assert sizeof(e) == 4;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun unsignedIntDeclarations() {\n        run(\n            \"\"\"\nint main()\n{\n    unsigned b = -1;\n    assert b > 0;\n    assert sizeof(b) == 4;\n\n\n    unsigned int d = -1;\n    assert d > 0;\n    assert sizeof(d) == 4;\n\n    int unsigned e = -1;\n    assert e > 0;\n    assert sizeof(e) == 4;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun typedefAnonymousStruct() {\n        run(\n            \"\"\"\ntypedef struct\n{\n    int x, y;\n    int z;\n} Point;\n\nvoid add(Point * a, Point * b, Point * s)\n{\n    s->x = a->x + b->x;\n    s->y = a->y + b->y;\n    s->z = a->z + b->z;\n}\n\nint main()\n{\n    Point p = {2, 3, 5};\n    Point q = {7, 11, 13};\n    Point r;\n    add(&p, &q, &r);\n    assert r.x == 9;\n    assert r.y == 14;\n    assert r.z == 18;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun multipleAnonymousStructs() {\n        run(\n            \"\"\"\ntypedef struct\n{\n    int x, y;\n} Point2D;\n\ntypedef struct\n{\n    int x, y;\n    int z;\n} Point3D;\n\nint main()\n{\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun missingParameterNames() {\n        run(\n            \"\"\"\nint square(int);\n\nint twice(int(int), int);\n\nint main()\n{\n    assert twice(square, 3) == 81;\n    return 0;\n}\n\nint twice(int f(int), int x)\n{\n    return f(f(x));\n}\n\nint square(int x)\n{\n    return x * x;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun trailingCommaInArrayInInitializerList() {\n        run(\n            \"\"\"\nint main()\n{\n    int a[] = {\n        2,\n        3,\n        5,\n        7,\n    };\n    assert sizeof a == 16;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun anonymousFunctionParameter() {\n        run(\n            \"\"\"\nint foo(int (x));\n\ntypedef int x;\n\nint bar(int (x));\n\nint main()\n{\n    sizeof foo(42);\n    sizeof bar(foo);\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun parameterShadowsGlobalTypedef() {\n        run(\n            \"\"\"\ntypedef int x;\n\nvoid foo(int x)\n{\n    int y = 1;\n    // The following line is now parsed as a multiplication,\n    // because x is the int parameter, not the global typedef.\n    x * y;\n    // Previously, this was a duplicate definition of y (as a pointer to int).\n}\n\nint main()\n{\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun parameterScopeIsClosed() {\n        run(\n            \"\"\"\ntypedef int x;\n\nx a;\n\nvoid foo(int x);\n\nx b;\n\nvoid foo(int x)\n{\n}\n\nx c;\n\nint main()\n{\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun signedLongDeclarations() {\n        run(\n            \"\"\"\nint main()\n{\n    long a = -1;\n    assert a < 0;\n    assert sizeof(a) == 4;\n\n\n    long int b = -1;\n    assert b < 0;\n    assert sizeof(b) == 4;\n\n    int long c = -1;\n    assert c < 0;\n    assert sizeof(c) == 4;\n\n\n    signed long d = -1;\n    assert d < 0;\n    assert sizeof(d) == 4;\n\n    long signed e = -1;\n    assert e < 0;\n    assert sizeof(e) == 4;\n\n\n    signed long int f = -1;\n    assert f < 0;\n    assert sizeof(f) == 4;\n\n    signed int long g = -1;\n    assert g < 0;\n    assert sizeof(g) == 4;\n\n    long signed int h = -1;\n    assert h < 0;\n    assert sizeof(h) == 4;\n\n    long int signed i = -1;\n    assert i < 0;\n    assert sizeof(i) == 4;\n\n    int signed long j = -1;\n    assert j < 0;\n    assert sizeof(j) == 4;\n\n    int long signed k = -1;\n    assert k < 0;\n    assert sizeof(k) == 4;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun unsignedLongDeclarations() {\n        run(\n            \"\"\"\nint main()\n{\n    unsigned long d = -1;\n    assert d > 0;\n    assert sizeof(d) == 4;\n\n    long unsigned e = -1;\n    assert e > 0;\n    assert sizeof(e) == 4;\n\n\n    unsigned long int f = -1;\n    assert f > 0;\n    assert sizeof(f) == 4;\n\n    unsigned int long g = -1;\n    assert g > 0;\n    assert sizeof(g) == 4;\n\n    long unsigned int h = -1;\n    assert h > 0;\n    assert sizeof(h) == 4;\n\n    long int unsigned i = -1;\n    assert i > 0;\n    assert sizeof(i) == 4;\n\n    int unsigned long j = -1;\n    assert j > 0;\n    assert sizeof(j) == 4;\n\n    int long unsigned k = -1;\n    assert k > 0;\n    assert sizeof(k) == 4;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun arraySizeConstantExpression() {\n        run(\n            \"\"\"\nint main()\n{\n    short a[3 * 7];\n    assert sizeof a == 42;\n\n    short b[sizeof a / 2];\n    assert sizeof b == 42;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun octalSingleDigit() {\n        run(\n            \"\"\"\nint main()\n{\n    assert 00 == 0;\n    assert 01 == 1;\n    assert 02 == 2;\n    assert 03 == 3;\n    assert 04 == 4;\n    assert 05 == 5;\n    assert 06 == 6;\n    assert 07 == 7;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun octalAllDigits() {\n        run(\n            \"\"\"\nint main()\n{\n    assert 01234567 == 342391;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun nonOctalFloat() {\n        run(\n            \"\"\"\nint main()\n{\n    assert 010f == 10;\n\n    assert 08f == 8;\n    assert 09f == 9;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun nonOctalDouble() {\n        run(\n            \"\"\"\nint main()\n{\n    assert 010. == 10;\n\n    assert 08. == 8;\n    assert 09. == 9;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun hexSingleDigit() {\n        run(\n            \"\"\"\nint main()\n{\n    assert 0x0 == 0;\n    assert 0x1 == 1;\n    assert 0x2 == 2;\n    assert 0x3 == 3;\n    assert 0x4 == 4;\n    assert 0x5 == 5;\n    assert 0x6 == 6;\n    assert 0x7 == 7;\n    assert 0x8 == 8;\n    assert 0x9 == 9;\n\n    assert 0xA == 10;\n    assert 0xB == 11;\n    assert 0xC == 12;\n    assert 0xD == 13;\n    assert 0xE == 14;\n    assert 0xF == 15;\n\n    assert 0xa == 10;\n    assert 0xb == 11;\n    assert 0xc == 12;\n    assert 0xd == 13;\n    assert 0xe == 14;\n    assert 0xf == 15;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun hexAllDigits() {\n        run(\n            \"\"\"\nint main()\n{\n    assert 0x01234567 == 19088743;\n\n    assert 0x89abcdef == 2309737967;\n    assert 0x89ABCDEF == 2309737967;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun binaryLiterals() {\n        run(\n            \"\"\"\nint main()\n{\n    assert 0b0 == 0;\n    assert 0b1 == 1;\n\n    assert 0b10 == 2;\n    assert 0b11 == 3;\n\n    assert 0b100 == 4;\n    assert 0b101 == 5;\n    assert 0b110 == 6;\n    assert 0b111 == 7;\n\n    assert 0b1000 == 8;\n    assert 0b1001 == 9;\n    assert 0b1010 == 10;\n    assert 0b1011 == 11;\n    assert 0b1100 == 12;\n    assert 0b1101 == 13;\n    assert 0b1110 == 14;\n    assert 0b1111 == 15;\n\n    assert 0b01001001100101100000001011010010 == 1234567890;\n    assert 0b10001011110100000011100000110101 == 2345678901;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun localFunctionPrototype() {\n        run(\n            \"\"\"\nint main()\n{\n    int square(int);\n    assert square(9) == 81;\n    return 0;\n}\n\nint square(int x)\n{\n    return x * x;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun enumUninitialized() {\n        run(\n            \"\"\"\nenum dir { north, east, south, west }\nsun = east;\n\nint main()\n{\n    enum dir x = 0;\n    assert x == north;\n\n    ++x;\n    assert x == sun;\n\n    ++x;\n    assert x == south;\n\n    ++x;\n    assert x == west;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun enumInitialized() {\n        run(\n            \"\"\"\nenum { Y = 6 };\n\nint main()\n{\n    enum { X = 7 };\n    char a[Y][X];\n    assert sizeof a == 42;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun enumMixed() {\n        run(\n            \"\"\"\nenum numbers {\n    a = 4,\n    b = 8,\n    c = 15,\n    d,\n    e = 23,\n    f = 42\n};\n\nint main()\n{\n    assert a == 4;\n    assert b == 8;\n    assert c == 15;\n    assert d == 16;\n    assert e == 23;\n    assert f == 42;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun staticInitializationArithmetic() {\n        run(\n            \"\"\"\nchar a;\nunsigned char b;\nshort c;\nunsigned short d;\nint e;\nunsigned int f;\nfloat g;\ndouble h;\n\nint main()\n{\n    assert a == 0;\n    assert b == 0;\n    assert c == 0;\n    assert d == 0;\n    assert e == 0;\n    assert f == 0;\n    assert g == 0;\n    assert h == 0;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun staticInitializationArray() {\n        run(\n            \"\"\"\nint a[5];\n\nint main()\n{\n    assert a[0] == 0;\n    assert a[1] == 0;\n    assert a[2] == 0;\n    assert a[3] == 0;\n    assert a[4] == 0;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun staticInitializationStruct() {\n        run(\n            \"\"\"\nstruct Point\n{\n    int x, y, z;\n} p;\n\nint main()\n{\n    assert p.x == 0;\n    assert p.y == 0;\n    assert p.z == 0;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun staticInitializationNested() {\n        run(\n            \"\"\"\nstruct Person\n{\n    char name[20];\n    int age;\n} a[2];\n\nint main()\n{\n    assert a[0].name[0] == 0;\n    assert a[0].name[19] == 0;\n    assert a[0].age == 0;\n\n    assert a[1].name[0] == 0;\n    assert a[1].name[19] == 0;\n    assert a[1].age == 0;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun staticInitializationLocal() {\n        run(\n            \"\"\"\nint a;\n\nint main()\n{\n    int b = 42;\n    static int c;\n\n    assert a == 0;\n    assert c == 0;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun functionPointersAreConstantExpressions() {\n        run(\n            \"\"\"\nint square(int x)\n{\n    return x * x;\n}\n\nint (*fp)(int) = &square;\n\nint main()\n{\n    assert fp(3) == 9;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun signedUnsignedComparisons() {\n        run(\n            \"\"\"\nint main()\n{\n    assert -1 == 0xffffffff;\n    unsigned z = 0;\n    assert z < -1;\n    assert z <= -1;\n    assert -1 > z;\n    assert -1 >= z;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun realloc() {\n        run(\n            \"\"\"\nint main()\n{\n    int * p = malloc(12);\n    p[0] = 2;\n    p[1] = 3;\n    p[2] = 5;\n\n    p = realloc(p, 16);\n    p[3] = 7;\n\n    assert p[0] == 2;\n    assert p[1] == 3;\n    assert p[2] == 5;\n    assert p[3] == 7;\n\n    free(p);\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun simpleContinue() {\n        run(\n            \"\"\"\nint main()\n{\n    int x = 0;\n    int i = 0;\n    for (i = 0; i <= 12; ++i)\n    {\n        if (i % 2 == 0) continue;\n        if (i % 3 == 0) continue;\n        x += i;\n    }\n    assert(x == 1+5+7+11);\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun innerContinue() {\n        run(\n            \"\"\"\nint main()\n{\n    int n = 0;\n    int i = 0;\n    for (i = 1; i <= 10; ++i)\n    {\n        int j = 0;\n        for (j = 1; j <= 10; ++j)\n        {\n            if (i == j) continue;\n            ++n;\n        }\n    }\n    assert(n == 100 - 10);\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun outerContinue() {\n        run(\n            \"\"\"\nint main()\n{\n    int n = 0;\n    int i = 0;\n    for (i = 1; i <= 10; ++i)\n    {\n        if (i % 2 == 0) continue;\n        while (0)\n        {\n            --i;\n        }\n        ++n;\n    }\n    assert(n == 5);\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun simpleBreak() {\n        run(\n            \"\"\"\nint main()\n{\n    int n = 0;\n    int i = 0;\n    for (i = 1; i <= 10; ++i)\n    {\n        ++n;\n        if (i == 5) break;\n        ++n;\n    }\n    assert(n == 5 + 4);\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun simpleGoto() {\n        run(\n            \"\"\"\nint main()\n{\n    int x = 0;\n    int y = 0;\n    int z = 0;\n\n    ++x;\n    goto increment_z;\n    ++y;\nincrement_z:\n    ++z;\n\n    assert x == 1;\n    assert y == 0;\n    assert z == 1;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun simulateDoWhileWithGoto() {\n        run(\n            \"\"\"\nint main()\n{\n    int sum = 0;\n    int i = 1;\n\nloop:\n    sum += i;\n    ++i;\n    if (i <= 10) goto loop;\n\n    assert sum == 55;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun fallthrough() {\n        run(\n            \"\"\"\nint log10(int x)\n{\n    int log = 0;\n    switch (x)\n    {\n        case 1000000000: ++log;\n        case 100000000: ++log;\n        case 10000000: ++log;\n        case 1000000: ++log;\n        case 100000: ++log;\n        case 10000: ++log;\n        case 1000: ++log;\n        case 100: ++log;\n        case 10: ++log;\n        case 1: return log;\n        default: return -1;\n    }\n}\n\nint main()\n{\n    assert 0 == log10(1);\n    assert 1 == log10(10);\n    assert 2 == log10(100);\n    assert 3 == log10(1000);\n    assert 4 == log10(10000);\n    assert 5 == log10(100000);\n    assert 6 == log10(1000000);\n    assert 7 == log10(10000000);\n    assert 8 == log10(100000000);\n    assert 9 == log10(1000000000);\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun defaultAboveOthers() {\n        run(\n            \"\"\"\nint isPrime(int x)\n{\n    switch (x)\n    {\n        default: return 0;\n        case 2:\n        case 3:\n        case 5:\n        case 7: return 1;\n    }\n}\n\nint main()\n{\n    assert!isPrime(0);\n    assert!isPrime(1);\n    assert isPrime(2);\n    assert isPrime(3);\n    assert!isPrime(4);\n    assert isPrime(5);\n    assert!isPrime(6);\n    assert isPrime(7);\n    assert!isPrime(8);\n    assert!isPrime(9);\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun missingBreak() {\n        run(\n            \"\"\"\nconst char * color(int x)\n{\n    const char * result = \"\";\n    switch (x)\n    {\n        case 0:\n        result = \"red\";\n        break;\n\n        case 1:\n        result = \"green\";\n        // missing break\n\n        case 2:\n        result = \"blue\";\n        break;\n    }\n    return result;\n}\n\nint main()\n{\n    assert color(0) == \"red\";\n    assert color(1) == \"blue\";   // due to missing break\n    assert color(2) == \"blue\";\n    assert color(3) == \"\";\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun duffsDevice() {\n        run(\n            \"\"\"\nvoid duffsDevice(char * dst, const char * src, unsigned n)\n{\n    unsigned rest = n % 8;\n    n = n / 8;\n    switch (rest)\n    {\n        case 0: do { *dst++ = *src++;\n        case 7:      *dst++ = *src++;\n        case 6:      *dst++ = *src++;\n        case 5:      *dst++ = *src++;\n        case 4:      *dst++ = *src++;\n        case 3:      *dst++ = *src++;\n        case 2:      *dst++ = *src++;\n        case 1:      *dst++ = *src++;\n                } while (n--);\n    }\n}\n\nint main()\n{\n    char a[] = \"................\";\n    duffsDevice(a, \"0123456789\", 10);\n    assert a[0] == '0';\n    assert a[1] == '1';\n    assert a[2] == '2';\n    assert a[3] == '3';\n    assert a[4] == '4';\n    assert a[5] == '5';\n    assert a[6] == '6';\n    assert a[7] == '7';\n    assert a[8] == '8';\n    assert a[9] == '9';\n    assert a[10] == '.';\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun bitwiseNot() {\n        run(\n            \"\"\"\nint main()\n{\n    int i = 0;\n    i = ~i;\n    assert i == -1;\n\n    unsigned u = 0;\n    u = ~u;\n    assert u == 4294967295;\n\n    assert sizeof(~'a') == sizeof(int);\n    assert ~'a' == -98;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun signedShift() {\n        run(\n            \"\"\"\nint main()\n{\n    int x = 5;\n    x = x << 3;\n    assert x == 40;\n\n    x = x >> 2;\n    assert x == 10;\n\n    assert -1 >> 1 == -1;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun unsignedShift() {\n        run(\n            \"\"\"\nint main()\n{\n    assert 0x80000000 >> 1 == 0x40000000;\n    assert 0x80000000 << 1 == 0;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun voidParameterList() {\n        run(\n            \"\"\"\nint main(void)\n{\n    assert sizeof main() == sizeof(int);\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun bsearchPresentElements() {\n        run(\n            \"\"\"\nint less(const void * x, const void * y)\n{\n    const int * p = x;\n    const int * q = y;\n    int result = (*p < *q) ? -1 : (*p > *q);\n    return result;\n}\n\nint main(void)\n{\n    int a[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};\n    int i;\n    for (i = 0; i < 10; ++i)\n    {\n        assert bsearch(a + i, a, 10, 4, less) == a + i;\n    }\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun bsearchAbsentElements() {\n        run(\n            \"\"\"\nint less(const void * x, const void * y)\n{\n    const int * p = x;\n    const int * q = y;\n    int result = (*p < *q) ? -1 : (*p > *q);\n    return result;\n}\n\nint main(void)\n{\n    int a[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};\n    int b[] = {0, 1, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 25, 26, 27, 28, 30};\n    int i;\n    for (i = 0; i < 21; ++i)\n    {\n        assert bsearch(b + i, a, 10, 4, less) == a + 10;\n    }\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun localTypedefBackReference() {\n        run(\n            \"\"\"\nint main()\n{\n    typedef double a, b, c[sizeof(a)], d[sizeof(b)];\n\n    assert sizeof(a) == 8;\n    assert sizeof(b) == 8;\n    assert sizeof(c) == 64;\n    assert sizeof(d) == 64;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun globalTypedefBackReference() {\n        run(\n            \"\"\"\ntypedef double a, b, c[sizeof(a)], d[sizeof(b)];\n\nint main()\n{\n    assert sizeof(a) == 8;\n    assert sizeof(b) == 8;\n    assert sizeof(c) == 64;\n    assert sizeof(d) == 64;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun postfixAfterSizeof() {\n        run(\n            \"\"\"\nint main()\n{\n    char x = 'a';\n    assert sizeof(x)++ == 1;\n    assert sizeof x ++ == 1;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun conditionalBindsStrongerThanComma() {\n        run(\n            \"\"\"\nint main()\n{\n    assert (1 ? 2 : 3, 4) == 4;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun initEnumeratorWithSizeof() {\n        run(\n            \"\"\"\nenum { N = sizeof(int) };\n\nint main()\n{\n    assert N == 4;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun castConstVoidPointers() {\n        run(\n            \"\"\"\nint fruit_compare(const void * const v, const void * w)\n{\n    return *(const char * const *)v - *(const char * const * const)w;\n}\n\nint main()\n{\n    typedef const char * string;\n    string a = \"apple\", b = \"banana\", c = \"cherry\", d = \"date\", e = \"eggfruit\", f = \"fig\", g = \"grape\";\n    string fruits[] = {g, c, b, f, d, e, a};\n    qsort(fruits, sizeof fruits/sizeof*fruits, sizeof*fruits, fruit_compare);\n\n    assert fruits[0] == a;\n    assert fruits[1] == b;\n    assert fruits[2] == c;\n    assert fruits[3] == d;\n    assert fruits[4] == e;\n    assert fruits[5] == f;\n    assert fruits[6] == g;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun castIntToDouble() {\n        run(\n            \"\"\"\nint main()\n{\n    assert (double)1/2 == 0.5;\n\n    int i = 1;\n    assert (const double)i++/2 == 0.5;\n    assert i == 2;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun castArraySize() {\n        run(\n            \"\"\"\nint main()\n{\n    char pi[(int)3.1416];\n    char e[(int)2.71828];\n\n    assert sizeof pi == 3;\n    assert sizeof e == 2;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun castCaseLabels() {\n        run(\n            \"\"\"\nconst char * pronounce(int x)\n{\n    switch (x)\n    {\n        case 1: return \"one\";\n        case (int)2.71828: return \"two\";\n        case (int)3.1416: return \"three\";\n        default: return \"???\";\n    }\n}\n\nint main()\n{\n    assert pronounce(1) == \"one\";\n    assert pronounce(2) == \"two\";\n    assert pronounce(3) == \"three\";\n    assert pronounce(4) == \"???\";\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun switchCharCaseInt() {\n        run(\n            \"\"\"\nint main()\n{\n    const char x = 'A';\n    switch (x)\n    {\n        case 65: break;\n        default: assert 0;\n    }\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun switchUnsignedCaseInt() {\n        run(\n            \"\"\"\nint main()\n{\n    switch (0xffffffff)\n    {\n        case -1: break;\n        default: assert 0;\n    }\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun returnEarlyFromVoidFunction() {\n        run(\n            \"\"\"\nint lastSign;\n\nvoid setSign(int x)\n{\n    if (x < 0)\n    {\n        lastSign = -1;\n        return;\n    }\n    if (x > 0)\n    {\n        lastSign = +1;\n        return;\n    }\n    lastSign = 0;\n}\n\nint sign(int x)\n{\n    setSign(x);\n    return lastSign;\n}\n\nint main()\n{\n    assert sign(-42) == -1;\n    assert sign(0) == 0;\n    assert sign(+42) == +1;\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun sameOffsetInDifferentSegments() {\n        run(\n            \"\"\"\nint main()\n{\n    int * a = malloc(sizeof(int));\n    int * b = malloc(sizeof(int));\n    assert a != b;\n    assert !(a == b);\n    free(a);\n    free(b);\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun strlen() {\n        run(\n            \"\"\"\nint main()\n{\n    assert strlen(\"\") == 0;\n    assert strlen(\"C\") == 1;\n    assert strlen(\"in\") == 2;\n    assert strlen(\"the\") == 3;\n    assert strlen(\"name\") == 4;\n    assert strlen(\"brand\") == 5;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n\n    @Test\n    fun strcmp() {\n        run(\n            \"\"\"\nint main()\n{\n    assert strcmp(\"apple\", \"apple\") == 0;\n    assert strcmp(\"apple\", \"pear\") < 0;\n    assert strcmp(\"pear\", \"apple\") > 0;\n\n    assert strcmp(\"apple\", \"ape\") > 0;\n    assert strcmp(\"ape\", \"apple\") < 0;\n\n    assert strcmp(\"apple\", \"apply\") < 0;\n    assert strcmp(\"apply\", \"apple\") > 0;\n\n    assert strcmp(\"apple\", \"applepie\") < 0;\n    assert strcmp(\"applepie\", \"apple\") > 0;\n\n    assert strcmp(\"\", \"\") == 0;\n    assert strcmp(\"\", \"a\") < 0;\n    assert strcmp(\"a\", \"\") > 0;\n\n    return 0;\n}\n\"\"\"\n        )\n    }\n}\n"
  },
  {
    "path": "src/test/kotlin/semantic/types/TypeToStringTest.kt",
    "content": "package semantic.types\n\nimport org.junit.jupiter.api.Assertions.assertEquals\nimport org.junit.jupiter.api.Test\n\nclass TypeToStringTest {\n    @Test\n    fun array() {\n        assertEquals(\"int[10]\", ArrayType(10, SignedIntType).toString())\n    }\n\n    @Test\n    fun arrayOfArray() {\n        assertEquals(\"int[1][2]\", ArrayType(1, ArrayType(2, SignedIntType)).toString())\n    }\n\n    @Test\n    fun pointer() {\n        assertEquals(\"int*\", PointerType(SignedIntType).toString())\n    }\n\n    @Test\n    fun arrayOfPointers() {\n        assertEquals(\"int*[10]\", ArrayType(10, PointerType(SignedIntType)).toString())\n    }\n\n    @Test\n    fun pointerToArray() {\n        assertEquals(\"int(*)[10]\", PointerType(ArrayType(10, SignedIntType)).toString())\n    }\n\n    @Test\n    fun pointerToPointerToArray() {\n        assertEquals(\"int(**)[10]\", PointerType(PointerType(ArrayType(10, SignedIntType))).toString())\n    }\n\n    @Test\n    fun qsort() {\n        val predicate = FunctionType(SignedIntType, ConstVoidPointerType, ConstVoidPointerType).pointer()\n        val qsort = FunctionType(VoidType, VoidPointerType, UnsignedIntType, UnsignedIntType, predicate)\n\n        assertEquals(\"void(void*,unsigned int,unsigned int,int(*)(const void*,const void*))\", qsort.toString())\n    }\n\n    @Test\n    fun bsearch() {\n        val predicate = FunctionType(SignedIntType, ConstVoidPointerType, ConstVoidPointerType).pointer()\n        val bsearch = FunctionType(\n            VoidPointerType, ConstVoidPointerType, ConstVoidPointerType, UnsignedIntType, UnsignedIntType, predicate\n        )\n\n        assertEquals(\n            \"void*(const void*,const void*,unsigned int,unsigned int,int(*)(const void*,const void*))\",\n            bsearch.toString()\n        )\n    }\n\n    @Test\n    fun function() {\n        assertEquals(\"int()\", FunctionType(SignedIntType).toString())\n    }\n\n    @Test\n    fun functionReturningPointer() {\n        assertEquals(\"int*()\", FunctionType(PointerType(SignedIntType)).toString())\n    }\n\n    @Test\n    fun functionReturningPointerToPointer() {\n        assertEquals(\"int**()\", FunctionType(PointerType(PointerType(SignedIntType))).toString())\n    }\n\n    @Test\n    fun functionReturningPointerToArray() {\n        assertEquals(\"int(*())[10]\", FunctionType(PointerType(ArrayType(10, SignedIntType))).toString())\n    }\n\n    @Test\n    fun functionReturningPointerToFunction() {\n        val callback = PointerType(FunctionType(SignedIntType, SignedIntType, SignedIntType))\n        assertEquals(\"int(*(int(*)(int,int)))(int,int)\", FunctionType(callback, callback).toString())\n    }\n\n    @Test\n    fun constant() {\n        assertEquals(\"const int\", Const(SignedIntType).toString())\n    }\n\n    @Test\n    fun arrayOfConst() {\n        assertEquals(\"const int[10]\", ArrayType(10, Const(SignedIntType)).toString())\n    }\n\n    @Test\n    fun pointerToConst() {\n        assertEquals(\"const int*\", PointerType(Const(SignedIntType)).toString())\n    }\n\n    @Test\n    fun constPointer() {\n        assertEquals(\"int*const\", Const(PointerType(SignedIntType)).toString())\n    }\n\n    @Test\n    fun constPointerToConst() {\n        assertEquals(\"const int*const\", Const(PointerType(Const(SignedIntType))).toString())\n    }\n\n    @Test\n    fun constPointerToConstPointerToConst() {\n        assertEquals(\"const int*const*const\", Const(PointerType(Const(PointerType(Const(SignedIntType))))).toString())\n    }\n\n    @Test\n    fun constPointerToArray() {\n        assertEquals(\"int(*const)[10]\", Const(PointerType(ArrayType(10, SignedIntType))).toString())\n    }\n\n    @Test\n    fun constPointerToArrayOfConst() {\n        assertEquals(\"const int(*const)[10]\", Const(PointerType(ArrayType(10, Const(SignedIntType)))).toString())\n    }\n\n    @Test\n    fun constPointerToFunction() {\n        assertEquals(\n            \"int(*const)(int)\",\n            Const(PointerType(FunctionType(SignedIntType, SignedIntType))).toString()\n        )\n    }\n\n    @Test\n    fun arrayOfConstPointersToVoid() {\n        assertEquals(\"void*const[10]\", ArrayType(10, Const(VoidPointerType)).toString())\n    }\n\n    @Test\n    fun arrayOfConstPointersToConstVoid() {\n        assertEquals(\"const void*const[10]\", ArrayType(10, Const(ConstVoidPointerType)).toString())\n    }\n}\n"
  },
  {
    "path": "src/test/kotlin/syntax/lexer/LexerTest.kt",
    "content": "package syntax.lexer\n\nimport org.junit.jupiter.api.Assertions.assertEquals\nimport org.junit.jupiter.api.Assertions.assertSame\nimport org.junit.jupiter.api.Test\nimport syntax.lexer.TokenKind.IDENTIFIER\nimport syntax.lexer.TokenKind.STRING_LITERAL\n\nimport kotlin.random.Random\n\nclass LexerTest {\n    private var lexer = Lexer(\"\")\n\n    @Test\n    fun identifiers() {\n        lexer =\n            Lexer(\"a z a0 z9 a_z foo _bar the_quick_brown_fox_jumps_over_the_lazy_dog THE_QUICK_BROWN_FOX_JUMPS_OVER_THE_LAZY_DOG\")\n\n        expectIdentifier(\"a\")\n        expectIdentifier(\"z\")\n        expectIdentifier(\"a0\")\n        expectIdentifier(\"z9\")\n        expectIdentifier(\"a_z\")\n        expectIdentifier(\"foo\")\n        expectIdentifier(\"_bar\")\n        expectIdentifier(\"the_quick_brown_fox_jumps_over_the_lazy_dog\")\n        expectIdentifier(\"THE_QUICK_BROWN_FOX_JUMPS_OVER_THE_LAZY_DOG\")\n    }\n\n    @Test\n    fun stringLiterals() {\n        lexer = Lexer(\n            \"\"\"\n        \"hello\"\n        \"hi there\"\n        \"say \\\"hi\\\"\"\n        \"\\\"please\\\" is the magic word\"\n        \"use \\\\n for a new line\"\n        \"\"\"\n        )\n\n        expectStringLiteral(\"hello\")\n        expectStringLiteral(\"hi there\")\n        expectStringLiteral(\"\"\"say \"hi\"\"\"\")\n        expectStringLiteral(\"\"\"\"please\" is the magic word\"\"\")\n        expectStringLiteral(\"\"\"use \\n for a new line\"\"\")\n    }\n\n    @Test\n    fun singleLineComments() {\n        lexer = Lexer(\n            \"\"\"// comment #1\n        a\n        // comment #2\n        // comment #3\n        b\n        c // comment #4\n        d// comment #5\n        e//\"\"\"\n        )\n\n        expectIdentifier(\"a\")\n        expectIdentifier(\"b\")\n        expectIdentifier(\"c\")\n        expectIdentifier(\"d\")\n        expectIdentifier(\"e\")\n    }\n\n    @Test\n    fun multiLineComments() {\n        lexer = Lexer(\n            \"\"\"/*\n        comment #1\n        */\n        a   /* comment #2 */\n        b  /*/ comment #3*/\n        c /**/\n        d/***/\n        e /* / ** / *** /*/\n        f  /*\"\"\"\n        )\n\n        expectIdentifier(\"a\")\n        expectIdentifier(\"b\")\n        expectIdentifier(\"c\")\n        expectIdentifier(\"d\")\n        expectIdentifier(\"e\")\n        expectIdentifier(\"f\")\n    }\n\n    @Test\n    fun keywords() {\n        for (kind in TokenKind.KEYWORDS) {\n            lexemeRoundTrip(kind)\n        }\n    }\n\n    @Test\n    fun operatorsSeparators() {\n        for (kind in TokenKind.OPERATORS_SEPARATORS) {\n            lexemeRoundTrip(kind)\n        }\n    }\n\n    private fun lexemeRoundTrip(kindIn: TokenKind) {\n        val lexemeIn = kindIn.lexeme\n        lexer = Lexer(lexemeIn)\n        val kindOut = lexer.nextToken().kind\n        val lexemeOut = kindOut.lexeme\n        assertSame(lexemeIn, lexemeOut)\n    }\n\n    @Test\n    fun nearKeywords() {\n        for (kind in TokenKind.KEYWORDS) {\n            val keyword = kind.lexeme\n            val init = keyword.substring(0, keyword.length - 1)\n            val last = keyword.last()\n            identifierRoundTrip(init)\n            identifierRoundTrip(init + randomLetterOtherThan(last))\n            identifierRoundTrip(keyword + randomLetter())\n        }\n    }\n\n    private fun identifierRoundTrip(identifier: String) {\n        lexer = Lexer(identifier)\n        expectIdentifier(identifier)\n    }\n\n    private fun randomLetter(): Char = (Random.nextInt(26) + 97).toChar()\n\n    private fun randomLetterOtherThan(forbidden: Char): Char {\n        val ch = (Random.nextInt(26 - 1) + 97).toChar()\n        // ch is a random character between a and y.\n        // In case ch is the forbidden character, 'z' is available.\n        // All characters will be chosen with the same probability.\n        return if (ch == forbidden) 'z' else ch\n    }\n\n    private fun expectIdentifier(identifier: String) {\n        val token = lexer.nextToken()\n        assertEquals(IDENTIFIER, token.kind)\n        assertEquals(identifier, token.text)\n    }\n\n    private fun expectStringLiteral(stringLiteral: String) {\n        val token = lexer.nextToken()\n        assertEquals(STRING_LITERAL, token.kind)\n        assertEquals(stringLiteral, token.text)\n    }\n}\n"
  },
  {
    "path": "src/test/kotlin/syntax/parser/AutocompletionTest.kt",
    "content": "package syntax.parser\n\nimport org.junit.jupiter.api.Assertions.assertEquals\nimport org.junit.jupiter.api.Test\n\nclass AutocompletionTest {\n    @Test\n    fun fullSuffix() {\n        val actual = autocompleteIdentifier(\"int foo, bar, baz; int main() { f\")\n        assertEquals(listOf(\"oo\"), actual)\n    }\n\n    @Test\n    fun partialSuffix() {\n        val actual = autocompleteIdentifier(\"int foo, bar, baz; int main() { b\")\n        assertEquals(listOf(\"a\"), actual)\n    }\n\n    @Test\n    fun ambiguous() {\n        val actual = autocompleteIdentifier(\"int foo, bar, baz; int main() { ba\")\n        assertEquals(listOf(\"r\", \"z\"), actual)\n    }\n\n    @Test\n    fun alreadyComplete() {\n        val actual = autocompleteIdentifier(\"int foo, bar, baz; int main() { foo\")\n        assertEquals(emptyList<String>(), actual)\n    }\n\n    @Test\n    fun parameter() {\n        val actual = autocompleteIdentifier(\"double f(double number, double numbest) { num\")\n        assertEquals(listOf(\"be\"), actual)\n    }\n\n    @Test\n    fun local() {\n        val actual = autocompleteIdentifier(\"double f() { double number, numbest; num\")\n        assertEquals(listOf(\"be\"), actual)\n    }\n\n    @Test\n    fun parameterAndLocal() {\n        val actual = autocompleteIdentifier(\"double f(double number) { double numbest; num\")\n        assertEquals(listOf(\"be\"), actual)\n    }\n\n    @Test\n    fun globalAndLocal() {\n        val actual = autocompleteIdentifier(\"double number; double f() { double numbest; num\")\n        assertEquals(listOf(\"be\"), actual)\n    }\n\n    @Test\n    fun nestedLocals() {\n        val actual = autocompleteIdentifier(\"double f() { double number; { double numbest; num\")\n        assertEquals(listOf(\"be\"), actual)\n    }\n\n    @Test\n    fun outOfScope() {\n        val actual = autocompleteIdentifier(\"double f() { double number; { double numbest; } num\")\n        assertEquals(listOf(\"ber\"), actual)\n    }\n\n    @Test\n    fun recursion() {\n        val actual = autocompleteIdentifier(\"void foo() { f\")\n        assertEquals(listOf(\"oo\"), actual)\n    }\n\n    @Test\n    fun backwardCall() {\n        val actual = autocompleteIdentifier(\"void foo() {} void bar() { f\")\n        assertEquals(listOf(\"oo\"), actual)\n    }\n\n    @Test\n    fun forwardCall() {\n        val actual = autocompleteIdentifier(\"void foo(); void bar() { f\")\n        assertEquals(listOf(\"oo\"), actual)\n    }\n\n    @Test\n    fun afterMutualRecursion() {\n        val actual = autocompleteIdentifier(\"void baz(); void bar() { baz(); } void baz() { bar(); } void foo() { b\")\n        assertEquals(listOf(\"a\"), actual)\n    }\n\n    @Test\n    fun enumerationConstant() {\n        val actual = autocompleteIdentifier(\"enum { WORD_SIZE = sizeof W\")\n        assertEquals(listOf(\"ORD_SIZE\"), actual)\n    }\n\n    @Test\n    fun directStructAccess() {\n        val actual =\n            autocompleteIdentifier(\"struct Person { int age; char name[12]; }; int noob; void f(struct Person p) { p.n\")\n        assertEquals(listOf(\"ame\"), actual)\n    }\n\n    @Test\n    fun indirectStructAccess() {\n        val actual =\n            autocompleteIdentifier(\"struct Person { int age; char name[12]; }; int noob; void f(struct Person * p) { p->n\")\n        assertEquals(listOf(\"ame\"), actual)\n    }\n\n    @Test\n    fun ignoreStruct() {\n        val actual = autocompleteIdentifier(\"struct Person { int age; char name[12]; }; int noob; void f() { n\")\n        assertEquals(listOf(\"oob\"), actual)\n    }\n}\n"
  },
  {
    "path": "src/test/resources/junit-platform.properties",
    "content": "junit.jupiter.execution.parallel.enabled = true\njunit.jupiter.execution.parallel.mode.default = concurrent\n"
  }
]