Browse Source

Implicit conversions??

dhasenan 2 years ago
parent
commit
19d1f293be

+ 14
- 2
jpetalc/src/main/java/org/ikeran/petal/semantic/SemPhase1.kt View File

@@ -34,15 +34,27 @@ class SemPhase1(val errors: ErrorRecorder): SemVisitor<Unit>() {
34 34
             type = type.resolve()
35 35
             node.type = type
36 36
         }
37
+        if (type is ForwardDeclType) {
38
+            errors.report(
39
+                node,
40
+                ErrorType.TYPE_NOT_FOUND,
41
+                "failed to locate type ${type.name}"
42
+            )
43
+        }
37 44
         if (init != null) {
38
-            logger.info("checking type ${init.type.name} vs ${node.type.name}")
39
-            if (init.type != type) {
45
+            logger.info("checking type ${init.type.name} vs ${type.name}")
46
+            if (init.type != type && !init.type.canImplicitConvertTo(type)) {
40 47
                 logger.info("adding error")
41 48
                 errors.report(
42 49
                         node,
43 50
                         ErrorType.TYPE_MISMATCH,
44 51
                         "can't initialize ${node.name} of type ${node.type.name} with ${init.type.name}")
45 52
             }
53
+            if (init.type != type) {
54
+                val cast = CastExpr(init, type, implicit = true)
55
+                cast.ast = init.ast
56
+                node.init = cast
57
+            }
46 58
         }
47 59
     }
48 60
 }

+ 3
- 0
jpetalc/src/main/java/org/ikeran/petal/semantic/SemVisitor.kt View File

@@ -118,4 +118,7 @@ abstract class SemVisitor<T> {
118 118
     open fun visitIntLiteral(node: IntLiteral): T { return defaultValue() }
119 119
     open fun visitFloatLiteral(node: FloatLiteral): T { return defaultValue() }
120 120
     open fun visitInvokeExpr(node: InvokeExpr): T { return defaultValue() }
121
+    open fun visitCastExpr(node: CastExpr): T {
122
+        return visit(node.child)
123
+    }
121 124
 }

+ 7
- 3
jpetalc/src/main/java/org/ikeran/petal/semantic/SemanticNodes.kt View File

@@ -103,13 +103,13 @@ class StringLiteral(val value: String): Expr(type = Type.STRING) {
103 103
     }
104 104
 }
105 105
 // TODO make this work for unsigned longs somehow
106
-class IntLiteral(val value: Long, type: Type = Type.INT): Expr(type) {
106
+class IntLiteral(val value: Long, type: Type = Type.NUMLITERAL): Expr(type) {
107 107
     override fun <T> accept(visitor: SemVisitor<T>): T {
108 108
         return visitor.visitIntLiteral(this)
109 109
     }
110 110
 
111 111
 }
112
-class FloatLiteral(val value: Double, type: Type = Type.FLOAT): Expr(type) {
112
+class FloatLiteral(val value: Double, type: Type = Type.NUMLITERAL): Expr(type) {
113 113
     override fun <T> accept(visitor: SemVisitor<T>): T {
114 114
         return visitor.visitFloatLiteral(this)
115 115
     }
@@ -119,5 +119,9 @@ class InvokeExpr(val parts: List<String>): Expr(type = Type.UNKNOWN) {
119 119
     override fun <T> accept(visitor: SemVisitor<T>): T {
120 120
         return visitor.visitInvokeExpr(this)
121 121
     }
122
-
122
+}
123
+class CastExpr(val child: Expr, type: Type, val implicit: Boolean): Expr(type = type) {
124
+    override fun <T> accept(visitor: SemVisitor<T>): T {
125
+        return visitor.visitCastExpr(this)
126
+    }
123 127
 }

+ 25
- 2
jpetalc/src/main/java/org/ikeran/petal/semantic/Types.kt View File

@@ -2,6 +2,7 @@ package org.ikeran.petal.semantic
2 2
 
3 3
 import java.util.ArrayList
4 4
 import java.util.HashMap
5
+import org.slf4j.LoggerFactory
5 6
 
6 7
 /**
7 8
  * Types that we know about.
@@ -31,6 +32,7 @@ abstract class Type(
31 32
         val UNKNOWN = UnknownType()
32 33
         val ERROR = ErrorType()
33 34
         val UNIT = UnitType()
35
+        val NUMLITERAL = NumberLiteralType()
34 36
 
35 37
         val registry = HashMap<String, Type>()
36 38
 
@@ -38,17 +40,21 @@ abstract class Type(
38 40
             val existing = registry.get(t.name)
39 41
             if (existing == null) {
40 42
                 registry.put(t.name, t)
43
+                logger.info("added ${t.name} -> ${t} to type registry")
41 44
                 return t
42 45
             }
43 46
             if (existing is ForwardDeclType && t !is ForwardDeclType) {
44 47
                 registry.put(t.name, t)
45 48
                 existing.realType = t
49
+                logger.info("added ${t.name} -> ${t} to type registry, overwriting fwd decl")
46 50
                 return t
47 51
             }
52
+            logger.info("returning existing type ${existing}")
48 53
             return existing
49 54
         }
50 55
 
51 56
         fun lookup(fqn: String): Type {
57
+            if (registry.size == 0) registerBuiltins()
52 58
             val fwd = ForwardDeclType(fqn)
53 59
             return register(fwd)
54 60
         }
@@ -70,14 +76,21 @@ abstract class Type(
70 76
             register(UNKNOWN)
71 77
             register(ERROR)
72 78
             register(UNIT)
79
+            register(NUMLITERAL)
73 80
         }
74 81
     }
75 82
 
76 83
     open fun isValid(): Boolean {
77 84
         return true
78 85
     }
86
+
87
+    open fun canImplicitConvertTo(other: Type): Boolean {
88
+        return other == this
89
+    }
79 90
 }
80 91
 
92
+val logger = LoggerFactory.getLogger("types")
93
+
81 94
 // Special cases
82 95
 /** UnknownType is the type initially assigned with eg `let a = someFunc()` and we don't know the func's return type. */
83 96
 class UnknownType(): Type("<unknown>") {
@@ -113,8 +126,18 @@ class ForwardDeclType(name: String): Type(name) {
113 126
         return other
114 127
     }
115 128
 }
129
+class NumberLiteralType: Type("<numeric>") {
130
+    override fun isValid(): Boolean { return false }
131
+    override fun canImplicitConvertTo(other: Type): Boolean {
132
+        logger.info("canImplicitConvertTo(${this} ${javaClass} to ${other} ${other.javaClass})")
133
+        if (other is NumberLiteralType) return true
134
+        if (other is IntType) return true
135
+        if (other is FloatType) return true
136
+        return false
137
+    }
138
+}
116 139
 // Builtin types
117
-data class IntType(val signed: Boolean, val size: Int) : Type("${if (signed) "" else "u"}int${size*8}}")
140
+data class IntType(val signed: Boolean, val size: Int) : Type("${if (signed) "" else "u"}int${size*8}")
118 141
 data class FloatType(val size: Int) : Type("float${size * 8}") {}
119 142
 class StringType : Type("string") {
120 143
     override fun equals(other: Any?): Boolean {
@@ -143,7 +166,7 @@ open class UserDefinedType(name: String = ""): Type(name) {
143 166
 }
144 167
 open class AggregateType(name: String = "") : Type(name)
145 168
 data class ClassType(val shortName: String, val qualifiedName: String) : AggregateType(qualifiedName) {
146
-    /** Only class Object should have a null parent. Otherwise, if the parent's null, we'll set it to Object. */
169
+    /** Only class ProtoObject should have a null parent. Otherwise, if the parent's null, we'll set it to Object. */
147 170
     var base: Type? = null
148 171
     val interfaces = ArrayList<InterfaceType>()
149 172
 }

+ 1
- 1
jpetalc/src/test/petal/semantic/test0003.petal View File

@@ -2,5 +2,5 @@ namespace test.
2 2
 #testerror 5:6
3 3
 # Typecheck in initialization with literal.
4 4
 main {
5
-    let int a = 10.0.
5
+    let int64 a = "hello".
6 6
 }

+ 14
- 0
jpetalc/src/test/petal/semantic/test0004.petal View File

@@ -0,0 +1,14 @@
1
+namespace test.
2
+# Number literals automatically convert to their related types.
3
+main {
4
+    let int8 b = 10.
5
+    let int16 b = 10.
6
+    let int32 b = 10.
7
+    let int64 b = 10.
8
+    let uint8 b = 10.
9
+    let uint16 b = 10.
10
+    let uint32 b = 10.
11
+    let uint64 b = 10.
12
+    let float32 b = 10.
13
+    let float64 b = 10.
14
+}

+ 1
- 0
petal.md View File

@@ -83,6 +83,7 @@ class MyClass
83 83
   provided. Python allows this but makes an implicit static variable, while D says it has to be a
84 84
   compile-time constant. If we said compile-time constant, that would mean bringing in null
85 85
   everywhere, and I don't want null.
86
+* Override functions don't need to mention their return types maybe?
86 87
 
87 88
 ## Metaprogramming
88 89
 I want easy metaprogramming. This means: