Skip to content

Commit

Permalink
fix: countless data structures & trait bugs, standardize errors
Browse files Browse the repository at this point in the history
  • Loading branch information
SrGaabriel committed Sep 6, 2024
1 parent b52df65 commit be0e65a
Show file tree
Hide file tree
Showing 31 changed files with 530 additions and 196 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,10 @@ func main() {
callback(4, lambda|x: int32| x + 24);
callback(8, lambda|x: int32| x + 36);
}
```
```

---

# Brand

The brand of the language is a leaf. The theme color is #f05133.
8 changes: 4 additions & 4 deletions analysis/src/commonMain/kotlin/Errors.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ sealed class AnalysisError(val message: String, val node: SyntaxTreeNode) {
)

class TraitForFunctionNotFound(node: SyntaxTreeNode, name: String, function: String) : AnalysisError(
"unknown trait: func `$function` for variable $name could not be found",
"unknown trait: func '$function' for variable $name could not be found",
node
)

Expand Down Expand Up @@ -84,7 +84,7 @@ sealed class AnalysisError(val message: String, val node: SyntaxTreeNode) {
currentModule: String,
functionModule: String,
) : AnalysisError(
"cannot call internal function `${node.name}(...)` from different module: $currentModule -> $functionModule",
"cannot call internal function '${node.name}(...)' from different module: $currentModule -> $functionModule",
node
)

Expand All @@ -108,7 +108,7 @@ sealed class AnalysisError(val message: String, val node: SyntaxTreeNode) {
function: String,
struct: String
) : AnalysisError(
"missing function `$function` for trait impl: $trait for $struct",
"missing function '$function' for trait impl: $trait for $struct",
node
)

Expand All @@ -124,7 +124,7 @@ sealed class AnalysisError(val message: String, val node: SyntaxTreeNode) {
struct: String,
correct: List<SeleneType>,
) : AnalysisError(
"wrong function signature `$function` in trait impl $trait for $struct, expected${
"wrong function signature '$function' in trait impl $trait for $struct, expected${
if (correct.isEmpty()) " no parameters"
else ": (${correct.joinToString(", ") { it.signature }})"
}",
Expand Down
9 changes: 9 additions & 0 deletions analysis/src/commonMain/kotlin/SymbolBlock.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class SymbolBlock(
var self: SeleneType? = parent?.self
) {
private val symbols = mutableMapOf<String, SeleneType>()
private val assignments = mutableMapOf<String, SyntaxTreeNode>()
private val definitions = mutableMapOf<SyntaxTreeNode, SeleneType>()

val name get() = when (id) {
Expand Down Expand Up @@ -59,10 +60,18 @@ class SymbolBlock(
definitions[node] = type
}

fun assignSymbol(name: String, node: SyntaxTreeNode) {
assignments[name] = node
}

fun resolveSymbol(name: String): SeleneType? {
return symbols[name] ?: parent?.resolveSymbol(name)
}

fun resolveAssignment(name: String): SyntaxTreeNode? {
return assignments[name] ?: parent?.resolveAssignment(name)
}

fun resolveExpression(node: SyntaxTreeNode): SeleneType? {
return when (node) {
is TypedSyntaxTreeNode -> node.type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class ArrayAnalyzer: SingleNodeAnalyzer<ArrayNode>(ArrayNode::class) {
): SymbolBlock {
val baseType = node.elements.firstOrNull()?.let {
block.resolveExpression(it)
} ?: SeleneType.Unknown
} ?: SeleneType.Undefined

val arrayType = if (node.dynamic) {
SeleneType.DynamicArray(baseType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class AssignmentAnalyzer: SingleNodeAnalyzer<AssignmentNode>(AssignmentNode::cla
} else {
block.defineSymbol(node, type)
}

block.assignSymbol(node.name, node.expression)
block.defineSymbol(node, type)
block.declareSymbol(node.name, type)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class BinaryOpAnalyzer: SingleNodeAnalyzer<BinaryOperatorNode>(BinaryOperatorNod
visitor: TypeInferenceVisitor
): SymbolBlock {
visitor.visit(node.left) {
block.defineSymbol(node, block.resolveExpression(node.left) ?: SeleneType.Unknown)
block.defineSymbol(node, block.resolveExpression(node.left) ?: SeleneType.Undefined)
}
return block
}
Expand All @@ -28,8 +28,8 @@ class BinaryOpAnalyzer: SingleNodeAnalyzer<BinaryOperatorNode>(BinaryOperatorNod
signatures: Signatures,
results: AnalysisResult
): SymbolBlock {
val left = block.resolveExpression(node.left) ?: SeleneType.Unknown
val right = block.resolveExpression(node.right) ?: SeleneType.Unknown
val left = block.resolveExpression(node.left) ?: SeleneType.Undefined
val right = block.resolveExpression(node.right) ?: SeleneType.Undefined

if (left != right) {
results.errors.add(
Expand Down
6 changes: 3 additions & 3 deletions analysis/src/commonMain/kotlin/analyzers/impl/CallAnalyzer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ class CallAnalyzer: SingleNodeAnalyzer<CallNode>(CallNode::class) {
) {
for ((index, argument) in node.arguments.withIndex()) {
visitor.visit(argument) {
val type = block.resolveExpression(argument) ?: SeleneType.Unknown
if (type == SeleneType.Unknown) {
val expectedType = parameters.getOrNull(index) ?: SeleneType.Unknown
val type = block.resolveExpression(argument) ?: SeleneType.Undefined
if (type == SeleneType.Undefined) {
val expectedType = parameters.getOrNull(index) ?: SeleneType.Undefined
block.defineSymbol(argument, expectedType)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import me.gabriel.selene.analysis.analyzers.TypeInferenceVisitor
import me.gabriel.selene.analysis.signature.Signatures
import me.gabriel.selene.analysis.util.doesProvidedTypeAccordToExpectedType
import me.gabriel.selene.frontend.SeleneType
import me.gabriel.selene.frontend.isUndefined
import me.gabriel.selene.frontend.mapBase
import me.gabriel.selene.frontend.parsing.InstantiationNode
import me.gabriel.selene.frontend.parsing.VariableReferenceNode

class InstantiationAnalyzer: SingleNodeAnalyzer<InstantiationNode>(InstantiationNode::class) {
override fun register(
Expand All @@ -24,7 +27,7 @@ class InstantiationAnalyzer: SingleNodeAnalyzer<InstantiationNode>(Instantiation
it.fields
)
}
?: SeleneType.Unknown
?: SeleneType.Undefined

block.defineSymbol(node, type)
return block
Expand Down Expand Up @@ -72,18 +75,36 @@ class InstantiationAnalyzer: SingleNodeAnalyzer<InstantiationNode>(Instantiation
}

val types = struct.fields.values.toList()
node.arguments.forEachIndexed { index, nodeArgument ->
node.arguments.forEachIndexed { index, argumentNode ->
val expectedType = types[index]
val providedType = block.resolveExpression(nodeArgument)
val providedType = block.resolveExpression(argumentNode)
println("Provided type for ${argumentNode} is $providedType")

if (providedType == null) {
results.errors.add(
AnalysisError.CouldNotResolveType(
nodeArgument,
nodeArgument.mark.value
argumentNode,
argumentNode.mark.value
)
)
return@forEachIndexed
}
if (providedType.isUndefined()) {
val newType = providedType.mapBase {
expectedType
}
block.defineSymbol(argumentNode,newType)
if (argumentNode is VariableReferenceNode) {
block.declareSymbol(argumentNode.name, newType)
val assignment = block.resolveAssignment(argumentNode.name)
if (assignment != null) {
println("Assigned node $assignment to $newType")
block.defineSymbol(assignment, newType)
}
}
println("New type for ${argumentNode} is $newType")
return@forEachIndexed
}

if (!doesProvidedTypeAccordToExpectedType(
provided = providedType,
Expand All @@ -92,7 +113,7 @@ class InstantiationAnalyzer: SingleNodeAnalyzer<InstantiationNode>(Instantiation
)) {
results.errors.add(
AnalysisError.WrongArgumentTypeForInstantiation(
node = nodeArgument,
node = argumentNode,
provided = providedType,
expected = expectedType
)
Expand Down
12 changes: 9 additions & 3 deletions analysis/src/commonMain/kotlin/analyzers/impl/LambdaAnalyzer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@ class LambdaAnalyzer: SingleNodeAnalyzer<LambdaNode>(LambdaNode::class) {
id = node
)

block.defineSymbol(node, SeleneType.Unknown)
val bodyType = block.resolveExpression(node.body)?.let {
SeleneType.Lambda(
node.parameters.map { it.type },
it
)
}
block.defineSymbol(node, bodyType ?: SeleneType.Undefined)
return newBlock
}

Expand All @@ -33,8 +39,8 @@ class LambdaAnalyzer: SingleNodeAnalyzer<LambdaNode>(LambdaNode::class) {
val lambdaBlock = block.surfaceSearchChild(node)
?: error("Lambda block not registered")

val type = block.resolveExpression(node) ?: SeleneType.Unknown
if (type == SeleneType.Unknown) {
val type = block.resolveExpression(node)
if (type == null) {
results.errors.add(
AnalysisError.LambdaTypeCannotBeInferred(
node
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class VariableReferenceAnalyzer: SingleNodeAnalyzer<VariableReferenceNode>(Varia
signatures: Signatures,
visitor: TypeInferenceVisitor
): SymbolBlock {
block.defineSymbol(node, block.resolveSymbol(node.name) ?: SeleneType.Unknown)
block.defineSymbol(node, block.resolveSymbol(node.name) ?: SeleneType.Undefined)
return block
}
}
2 changes: 1 addition & 1 deletion analysis/src/commonMain/kotlin/util/Types.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fun doesProvidedTypeAccordToExpectedType(
required: SeleneType,
signatures: Signatures
): Boolean {
if (required == SeleneType.Unknown || required == SeleneType.Any) {
if (required == SeleneType.Undefined || required == SeleneType.Any) {
return true
}
if (required is SeleneType.Mutable || provided is SeleneType.Mutable) {
Expand Down
Loading

0 comments on commit be0e65a

Please sign in to comment.