translator: add function call

This commit is contained in:
e5l
2016-07-11 16:10:08 +03:00
parent 968fc9ec03
commit a47b61d332
11 changed files with 95 additions and 44 deletions
@@ -4,7 +4,6 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.kotlinnative.translator.llvm.LLVMBuilder
import org.kotlinnative.translator.utils.FunctionDescriptor
import org.kotlinnative.translator.utils.KtType
class FileTranslator(val state: TranslationState, val file: KtFile) {
@@ -22,8 +21,8 @@ class FileTranslator(val state: TranslationState, val file: KtFile) {
is KtNamedFunction -> {
val function = FunctionCodegen(state, declaration, codeBuilder)
state.functions.put(function.name, FunctionDescriptor(
KtType(function.returnType),
function.args?.map { KtType(it.type) }?.toList() ?: listOf()
function.returnType,
function.args?.map { it.type }?.toList() ?: listOf()
))
function.generate()
@@ -4,18 +4,15 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtConstantExpression
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespaceAndComments
import org.jetbrains.kotlin.resolve.BindingContext
import org.kotlinnative.translator.llvm.LLVMBuilder
import org.kotlinnative.translator.llvm.LLVMDescriptorGenerate
import org.kotlinnative.translator.llvm.LLVMMapStandardType
import org.kotlinnative.translator.llvm.LLVMVariable
import org.kotlinnative.translator.debug.printFunction
import org.kotlinnative.translator.llvm.*
import org.kotlinnative.translator.llvm.types.LLVMIntType
import org.kotlinnative.translator.llvm.types.parseLLVMType
import org.kotlinnative.translator.utils.FunctionArgument
import java.util.*
class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction, val codeBuilder: LLVMBuilder) {
@@ -44,40 +41,59 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
codeBuilder.addLLVMCode(LLVMDescriptorGenerate(function.fqName.toString(), args, returnType))
}
private fun expressionWalker(expr: Any?) {
private fun expressionWalker(expr: PsiElement?) {
when (expr) {
is KtBlockExpression -> evaluateBlockExpression(expr)
is PsiElement -> evaluatePsiExpression(expr)
null -> Unit
is KtBlockExpression -> expressionWalker(expr.firstChild)
is KtProperty -> evaluateLeafPsiElement(expr.firstChild as LeafPsiElement)
is PsiElement -> evaluateExpression(expr.firstChild)
null -> return
else -> UnsupportedOperationException()
}
expressionWalker(expr?.getNextSiblingIgnoringWhitespaceAndComments())
}
private fun evaluateBlockExpression(expr: KtBlockExpression) {
expressionWalker(expr.firstChild)
expressionWalker(expr.getNextSiblingIgnoringWhitespaceAndComments())
}
private fun evaluatePsiExpression(expr: PsiElement) {
evaluateExpression(expr.firstChild)
evaluatePsiExpression(expr.getNextSiblingIgnoringWhitespaceAndComments() ?: return)
}
private fun evaluateExpression(expr: Any?): LLVMVariable? {
private fun evaluateExpression(expr: PsiElement?): LLVMNode? {
return when (expr) {
is KtBinaryExpression -> evaluateBinaryExpression(expr)
is KtConstantExpression -> evaluateConstantExpression(expr)
is KtCallExpression -> evaluateCallExpression(expr)
is PsiWhiteSpace -> null
is PsiElement -> evaluatePsiElement(expr)
is KtConstantExpression -> evaluateConstantExpression(expr)
null -> null
else -> throw UnsupportedOperationException()
}
}
private fun evaluateBinaryExpression(expr: KtBinaryExpression): LLVMVariable {
val left = evaluateExpression(expr.firstChild) ?: throw UnsupportedOperationException("Wrong binary exception")
val right = evaluateExpression(expr.lastChild) ?: throw UnsupportedOperationException("Wrong binary exception")
private fun evaluateCallExpression(expr: KtCallExpression): LLVMNode? {
val function = expr.firstChild.firstChild
val descriptor = state.functions[function.text] ?: return null
val names = parseArgList(expr
.firstChild
.getNextSiblingIgnoringWhitespaceAndComments()
?.firstChild)
return LLVMCall(descriptor.returnType, function.text, descriptor.argTypes.mapIndexed { i: Int, type: String -> LLVMVariable(names[i], parseLLVMType(type)) })
}
private fun parseArgList(argumentList: PsiElement?): List<String> {
val args = ArrayList<String>()
var currentArg = argumentList?.getNextSiblingIgnoringWhitespaceAndComments()
while (currentArg?.text != ")" && currentArg != null) {
args.add(currentArg?.text)
currentArg = currentArg
?.getNextSiblingIgnoringWhitespaceAndComments()
?.getNextSiblingIgnoringWhitespaceAndComments()
}
return args
}
private fun evaluateBinaryExpression(expr: KtBinaryExpression): LLVMNode {
val left = evaluateExpression(expr.firstChild) as LLVMVariable? ?: throw UnsupportedOperationException("Wrong binary exception")
val right = evaluateExpression(expr.lastChild) as LLVMVariable? ?: throw UnsupportedOperationException("Wrong binary exception")
val operator = expr.operationToken
return codeBuilder.addPrimitiveBinaryOperation(operator, left, right)
@@ -100,13 +116,24 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
private fun evaluateLeafPsiElement(element: LeafPsiElement): LLVMVariable? {
return when (element.elementType) {
KtTokens.RETURN_KEYWORD -> evaluateReturnInstruction(element)
KtTokens.VAL_KEYWORD -> evaluateValExpression(element)
KtTokens.VAR_KEYWORD -> evaluateValExpression(element)
else -> null
}
}
private fun evaluateValExpression(element: LeafPsiElement): LLVMVariable? {
val identifier = element.getNextSiblingIgnoringWhitespaceAndComments()
val eq = identifier?.getNextSiblingIgnoringWhitespaceAndComments() ?: return null
val assignExpression = evaluateExpression(eq?.getNextSiblingIgnoringWhitespaceAndComments()) ?: return null
codeBuilder.addAssignment(LLVMVariable(identifier!!.text), assignExpression)
return null
}
private fun evaluateReturnInstruction(element: LeafPsiElement): LLVMVariable? {
var next = element.getNextSiblingIgnoringWhitespaceAndComments();
val retVar = evaluateExpression(next)
var next = element.getNextSiblingIgnoringWhitespaceAndComments()
val retVar = evaluateExpression(next) as LLVMVariable
codeBuilder.addLLVMCode("ret i32 ${retVar?.label}")
return null
@@ -22,7 +22,7 @@ import org.kotlinnative.translator.utils.FunctionDescriptor
import java.util.*
class TranslationState(val sources: List<String>, disposer: Disposable) {
class TranslationState(sources: List<String>, disposer: Disposable) {
val environment: KotlinCoreEnvironment
val bindingContext: BindingContext
@@ -1,3 +1,3 @@
package org.kotlinnative.translator.exceptions
class TranslationException : Exception()
class TranslationException : Exception()
@@ -33,19 +33,24 @@ class LLVMBuilder {
KtTokens.PLUS -> "add nsw i32"
KtTokens.MINUS -> "sub nsw i32"
KtTokens.MUL -> "mul nsw i32"
else -> throw UnsupportedOperationException("Unkbown binary operator")
else -> throw UnsupportedOperationException("Unknown binary operator")
}
llvmCode.appendln("$newVar = $llvmOperator $firstOp, $secondOp")
return newVar
}
fun clean() {
llvmCode = StringBuilder()
}
fun addAssignment(llvmVariable: LLVMVariable, rhs: LLVMNode) {
llvmCode.appendln("%$llvmVariable = $rhs")
}
override fun toString(): String {
return llvmCode.toString()
}
}
@@ -0,0 +1,8 @@
package org.kotlinnative.translator.llvm
class LLVMCall(val returnType: String, val name: String, val arguments: List<LLVMVariable>) : LLVMNode() {
override fun toString(): String {
return "call $returnType $name(${arguments.joinToString { "${it.type} ${it.label}" }})"
}
}
@@ -3,10 +3,12 @@ package org.kotlinnative.translator.llvm
import org.kotlinnative.translator.llvm.types.LLVMType
import kotlin.reflect.KFunction0
class LLVMExpression(val variableType: KFunction0<LLVMType>, val llvmCode: String) : LLVMNode() {
open class LLVMExpression(val variableType: KFunction0<LLVMType>, val llvmCode: String) : LLVMNode() {
fun generateExpression(builder: LLVMBuilder): LLVMVariable {
val newVar = builder.getNewVariable(variableType);
builder.addLLVMCode("%$newVar = $llvmCode");
val newVar = builder.getNewVariable(variableType)
builder.addLLVMCode("%$newVar = $llvmCode")
return newVar
}
}
@@ -2,9 +2,10 @@ package org.kotlinnative.translator.llvm
import org.kotlinnative.translator.llvm.types.LLVMType
class LLVMVariable(val label: String, val type: LLVMType?) : LLVMNode() {
class LLVMVariable(val label: String, val type: LLVMType? = null) : LLVMNode() {
override fun toString(): String {
return label
}
}
@@ -5,9 +5,14 @@ import org.kotlinnative.translator.llvm.LLVMVariable
class LLVMIntType() : LLVMType() {
override fun operatorPlus(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression {
//TODO switch by types: int + double = int
return LLVMExpression(::LLVMIntType, "add nsw i32 $firstOp, $secondOp")
}
override fun toString(): String {
return "i32"
}
}
@@ -1,8 +1,14 @@
package org.kotlinnative.translator.llvm.types;
import org.kotlinnative.translator.exceptions.TranslationException
import org.kotlinnative.translator.llvm.LLVMExpression
import org.kotlinnative.translator.llvm.LLVMVariable
abstract class LLVMType() {
abstract fun operatorPlus(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression;
}
fun parseLLVMType(type: String): LLVMType = when(type) {
"i32" -> LLVMIntType()
else -> throw TranslationException()
}
@@ -2,6 +2,4 @@ package org.kotlinnative.translator.utils
data class FunctionArgument(val type: String, val name: String)
data class KtType(val name: String)
data class FunctionDescriptor(val returnType: KtType, val argTypes: List<KtType>)
data class FunctionDescriptor(val returnType: String, val argTypes: List<String>)