Skip to content

Commit 3e3cc88

Browse files
committed
parser: add ownership attributes on member vars to AST
1 parent 3673f04 commit 3e3cc88

10 files changed

Lines changed: 112 additions & 39 deletions
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package compiler.ast
2+
3+
import compiler.lexer.KeywordToken
4+
5+
sealed class AstBaseTypeMemberVariableAttribute(
6+
val attributeName: KeywordToken,
7+
) {
8+
fun conflictsWith(other: AstBaseTypeMemberVariableAttribute) = this.javaClass == other.javaClass && attributeName.keyword != other.attributeName.keyword
9+
10+
class Ownership(nameToken: KeywordToken) : AstBaseTypeMemberVariableAttribute(nameToken) {
11+
override fun equals(other: Any?): Boolean {
12+
if (this === other) return true
13+
if (other !is Ownership) return false
14+
15+
if (attributeName.keyword != other.attributeName.keyword) return false
16+
17+
return true
18+
}
19+
20+
override fun hashCode(): Int {
21+
var result = javaClass.hashCode()
22+
result = 31 * result + attributeName.hashCode()
23+
return result
24+
}
25+
26+
/** TODO: unused? */
27+
private enum class OwnershipKind { OWNED, REFERENCED }
28+
}
29+
}

frontend/src/main/kotlin/compiler/ast/BaseTypeDeclaration.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ sealed class BaseTypeMemberDeclaration : BaseTypeEntryDeclaration {
172172
}
173173

174174
class BaseTypeMemberVariableDeclaration(
175-
val attributes: List<KeywordToken>,
175+
val attributes: BoundBaseTypeMemberVariableAttributes,
176176
val variableDeclaration: VariableDeclaration,
177177
) : BaseTypeMemberDeclaration() {
178178
override val span = variableDeclaration.declaredAt
@@ -294,7 +294,7 @@ class BaseTypeMemberVariableDeclaration(
294294
boundLocalVariableInCtor,
295295
variableDeclaration.visibility?.bindTo(typeRootContext)
296296
?: BoundVisibility.default(typeRootContext),
297-
BoundBaseTypeMemberVariableAttributes(attributes),
297+
attributes,
298298
getTypeDef,
299299
this@BaseTypeMemberVariableDeclaration,
300300
)

frontend/src/main/kotlin/compiler/binding/BoundFunctionAttributeList.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import compiler.ast.AstFunctionAttribute
44
import compiler.ast.AstVisibility
55
import compiler.binding.context.CTContext
66
import compiler.diagnostic.Diagnosis
7-
import compiler.diagnostic.conflictingAttributes
7+
import compiler.diagnostic.conflictingFunctionAttributes
88
import compiler.diagnostic.functionIsMissingAttribute
99
import compiler.diagnostic.inefficientAttributes
1010
import compiler.diagnostic.unsupportedCallingConvention
@@ -80,7 +80,7 @@ class BoundFunctionAttributeList(
8080
attributes.twoElementPermutationsUnordered()
8181
.filter { (a, b) -> conflictsWith(a, b) }
8282
.forEach { (a, b) ->
83-
diagnosis.conflictingAttributes(listOf(a, b))
83+
diagnosis.conflictingFunctionAttributes(listOf(a, b))
8484
}
8585

8686
attributes
Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,35 @@
11
package compiler.binding.basetype
22

3+
import compiler.ast.AstBaseTypeMemberVariableAttribute
34
import compiler.diagnostic.Diagnosis
5+
import compiler.diagnostic.conflictingMemberVariableAttributes
46
import compiler.diagnostic.duplicateMemberVariableAttributes
5-
import compiler.diagnostic.invalidMemberVariableAttribute
6-
import compiler.lexer.KeywordToken
7+
import compiler.util.twoElementPermutationsUnordered
78

89
class BoundBaseTypeMemberVariableAttributes(
9-
val astNodes: List<KeywordToken>,
10+
val attributes: List<AstBaseTypeMemberVariableAttribute>,
1011
) {
11-
fun validate(diagnosis: Diagnosis) {
12-
val (applicableAttrs, inapplicableAttrs) = astNodes.partition { false } /* no attributes known currently */
13-
inapplicableAttrs.forEach {
14-
diagnosis.invalidMemberVariableAttribute(it, "${it.keyword.text} is not a valid attribute on member variables")
15-
}
12+
val ownershipAttribute: AstBaseTypeMemberVariableAttribute.Ownership?
13+
14+
init {
15+
ownershipAttribute = attributes
16+
.filterIsInstance<AstBaseTypeMemberVariableAttribute.Ownership>()
17+
.firstOrNull()
18+
}
1619

17-
applicableAttrs
18-
.groupBy { it.keyword }
20+
fun validate(diagnosis: Diagnosis) {
21+
attributes
22+
.groupBy { it.attributeName.keyword }
1923
.values
2024
.filter { it.size > 1 }
2125
.forEach { dupes ->
2226
diagnosis.duplicateMemberVariableAttributes(dupes.first(), dupes.drop(1))
2327
}
28+
29+
attributes.twoElementPermutationsUnordered()
30+
.filter { (a, b) -> a.conflictsWith(b) }
31+
.forEach { (a, b) ->
32+
diagnosis.conflictingMemberVariableAttributes(listOf(a, b))
33+
}
2434
}
2535
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package compiler.diagnostic
2+
3+
import compiler.ast.AstBaseTypeMemberVariableAttribute
4+
import compiler.diagnostic.rendering.CellBuilder
5+
6+
class ConflictingBaseTypeMemberVariableAttributesDiagnostic(
7+
val attributesInConflict: List<AstBaseTypeMemberVariableAttribute>,
8+
) : Diagnostic(
9+
Severity.ERROR,
10+
"These attributes contradict each other",
11+
attributesInConflict.first().attributeName.span,
12+
) {
13+
context(builder: CellBuilder)
14+
override fun renderBody() {
15+
builder.sourceHints(*attributesInConflict.map { SourceHint(it.attributeName.span, severity = severity) }.toTypedArray())
16+
}
17+
}
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
package compiler.diagnostic
22

3+
import compiler.ast.AstBaseTypeMemberVariableAttribute
34
import compiler.diagnostic.rendering.CellBuilder
4-
import compiler.lexer.KeywordToken
55

66
class DuplicateMemberVariableAttributeDiagnostic(
7-
val duplicates: List<KeywordToken>,
7+
val duplicates: List<AstBaseTypeMemberVariableAttribute>,
88
) : Diagnostic(
99
Severity.WARNING,
10-
"Duplicate member variable attribute ${duplicates.first().keyword.text}",
11-
duplicates.first().span,
10+
"Duplicate member variable attribute ${duplicates.first().attributeName.keyword.text}",
11+
duplicates.first().attributeName.span,
1212
) {
1313
context(builder: CellBuilder)
1414
override fun renderBody() {
1515
with(builder) {
16-
sourceHints(duplicates.map { SourceHint(it.span, severity = severity) })
16+
sourceHints(duplicates.map { SourceHint(it.attributeName.span, severity = severity) })
1717
}
1818
}
1919
}

frontend/src/main/kotlin/compiler/diagnostic/InvalidBaseTypeMemberVariableAttributeDiagnostic.kt

Lines changed: 0 additions & 12 deletions
This file was deleted.

frontend/src/main/kotlin/compiler/diagnostic/factory.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package compiler.diagnostic
22

3+
import compiler.ast.AstBaseTypeMemberVariableAttribute
34
import compiler.ast.AstFunctionAttribute
45
import compiler.ast.AstPackageName
56
import compiler.ast.BaseTypeConstructorDeclaration
@@ -62,7 +63,6 @@ import compiler.binding.type.BoundTypeReference
6263
import compiler.binding.type.ErroneousType
6364
import compiler.binding.type.TypeUseSite
6465
import compiler.lexer.IdentifierToken
65-
import compiler.lexer.KeywordToken
6666
import compiler.lexer.OperatorToken
6767
import compiler.lexer.Span
6868
import io.github.tmarsteel.emerge.common.CanonicalElementName
@@ -229,16 +229,16 @@ fun Diagnosis.inefficientAttributes(message: String, attributes: Collection<AstF
229229
add(ModifierInefficiencyDiagnostic(message, attributes))
230230
}
231231

232-
fun Diagnosis.conflictingAttributes(attributes: Collection<AstFunctionAttribute>) {
232+
fun Diagnosis.conflictingFunctionAttributes(attributes: Collection<AstFunctionAttribute>) {
233233
add(ConflictingFunctionAttributesDiagnostic(attributes))
234234
}
235235

236-
fun Diagnosis.invalidMemberVariableAttribute(attribute: KeywordToken, reason: String) {
237-
add(InvalidBaseTypeMemberVariableAttributeDiagnostic(reason, attribute.span))
236+
fun Diagnosis.duplicateMemberVariableAttributes(firstMention: AstBaseTypeMemberVariableAttribute, duplicates: List<AstBaseTypeMemberVariableAttribute>) {
237+
add(DuplicateMemberVariableAttributeDiagnostic(duplicates))
238238
}
239239

240-
fun Diagnosis.duplicateMemberVariableAttributes(firstMention: KeywordToken, duplicates: List<KeywordToken>) {
241-
add(DuplicateMemberVariableAttributeDiagnostic(duplicates))
240+
fun Diagnosis.conflictingMemberVariableAttributes(attributesInConflict: List<AstBaseTypeMemberVariableAttribute>) {
241+
add(ConflictingBaseTypeMemberVariableAttributesDiagnostic(attributesInConflict))
242242
}
243243

244244
fun Diagnosis.toplevelFunctionWithOverrideAttribute(attr: AstFunctionAttribute.Override) {

frontend/src/main/kotlin/compiler/lexer/tokens.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ enum class Keyword(val text: String)
4040
IMMUTABLE("const"),
4141
EXCLUSIVE("exclusive"),
4242

43+
OWN("own"),
44+
REF("ref"),
45+
46+
SHARED("shared"),
47+
STATIC("static"),
48+
ABSTRACT("abstract"),
49+
FINAL("final"),
50+
SEALED("sealed"),
51+
VIRTUAL("virtual"),
52+
4353
NOTHROW("nothrow"),
4454
PURE("pure"),
4555
OPERATOR("operator"),

frontend/src/main/kotlin/compiler/parser/grammar/basetype.kt

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
package compiler.parser.grammar
2020

21+
import compiler.ast.AstBaseTypeMemberVariableAttribute
2122
import compiler.ast.AstCodeChunk
2223
import compiler.ast.AstFunctionAttribute
2324
import compiler.ast.AstVisibility
@@ -32,7 +33,9 @@ import compiler.ast.TypeParameterBundle
3233
import compiler.ast.VariableDeclaration
3334
import compiler.ast.type.TypeParameter
3435
import compiler.ast.type.TypeReference
36+
import compiler.binding.basetype.BoundBaseTypeMemberVariableAttributes
3537
import compiler.lexer.IdentifierToken
38+
import compiler.lexer.Keyword
3639
import compiler.lexer.Keyword.CLASS_DEFINITION
3740
import compiler.lexer.Keyword.CONSTRUCTOR
3841
import compiler.lexer.Keyword.DESTRUCTOR
@@ -46,14 +49,30 @@ import compiler.parser.grammar.dsl.astTransformation
4649
import compiler.parser.grammar.dsl.eitherOf
4750
import compiler.parser.grammar.dsl.sequence
4851

52+
val BaseTypeMemberVariableAttribute = eitherOf {
53+
keyword(Keyword.OWN)
54+
keyword(Keyword.REF)
55+
}
56+
.astTransformation { tokens ->
57+
val keywordToken = tokens.next() as KeywordToken
58+
when (keywordToken.keyword) {
59+
Keyword.OWN,
60+
Keyword.REF -> AstBaseTypeMemberVariableAttribute.Ownership(keywordToken)
61+
else -> error("unsupported grammar")
62+
}
63+
}
64+
4965
val BaseTypeMemberVariableDeclaration = sequence("member variable declaration") {
66+
repeating {
67+
ref(BaseTypeMemberVariableAttribute)
68+
}
5069
ref(VariableDeclaration)
5170
operator(NEWLINE)
5271
}
5372
.astTransformation { tokens ->
54-
val attributes = tokens.takeWhileIsInstanceOf<KeywordToken>()
73+
val attributes = tokens.takeWhileIsInstanceOf<AstBaseTypeMemberVariableAttribute>()
5574
BaseTypeMemberVariableDeclaration(
56-
attributes,
75+
BoundBaseTypeMemberVariableAttributes(attributes),
5776
tokens.next() as VariableDeclaration,
5877
)
5978
}

0 commit comments

Comments
 (0)