Pass all but one test

This commit is contained in:
Sasha Koshka 2023-11-04 16:34:40 -04:00
parent a2e22d1154
commit 47beb9e41f
8 changed files with 130 additions and 54 deletions

View File

@ -15,6 +15,8 @@ type strictness int; const (
weak
// structural equivalence
structural
// allow if values can be converted
coerce
// assignment rules are completely ignored and everything is accepted
force
)
@ -28,15 +30,38 @@ func (this *Tree) canAssign (
mode strictness,
source entity.Type,
) error {
fail := func () error {
switch mode {
case strict:
return participle.Errorf(pos, "expected %v", destination)
case weak:
return participle.Errorf (
pos, "cannot use %v as %v",
source, destination)
case structural:
return participle.Errorf (
pos, "cannot convert from %v to %v",
source, destination)
default:
panic(fmt.Sprint (
"BUG: analyze doesnt know about mode ", mode))
}
}
// short circuit if force is selected
if mode == force { return nil }
// check for coerce strictness
if mode == coerce {
return this.canAssignCoerce(pos, destination, source)
}
// do structural equivalence if structural is selected
if mode == structural {
if this.areStructurallyEquivalent(destination, source) {
return nil
} else {
return participle.Errorf(pos, "expected %v", destination)
return fail()
}
}
@ -82,7 +107,54 @@ func (this *Tree) canAssign (
*entity.TypeBool:
if !destination.Equals(source) {
return participle.Errorf(pos, "expected %v", destination)
return fail()
}
default: panic(fmt.Sprint("BUG: analyzer doesnt know about type ", destination))
}
return nil
}
func (this *Tree) canAssignCoerce (
pos lexer.Position,
destination entity.Type,
source entity.Type,
) error {
fail := func () error {
return participle.Errorf (
pos, "cannot convert from %v to %v",
source, destination)
}
destination = this.reduceToBase(destination)
source = this.reduceToBase(source)
switch destination.(type) {
// no type
case nil:
return nil
// base type
case *entity.TypeInt,
*entity.TypeFloat,
*entity.TypeWord,
*entity.TypeBool:
switch source.(type) {
case *entity.TypeInt,
*entity.TypeFloat,
*entity.TypeWord,
*entity.TypeBool: return nil
default: return fail()
}
case *entity.TypePointer,
*entity.TypeSlice,
*entity.TypeArray,
*entity.TypeStruct:
if !destination.Equals(source) {
return fail()
}
default: panic(fmt.Sprint("BUG: analyzer doesnt know about type ", destination))
@ -132,8 +204,6 @@ func (this *Tree) canAssignInterface (
"Tree.analyzeMethodOrBehavior returned ",
method))
}
fmt.Println(signature, behavior)
// check equivalence
if !signature.Equals(behavior) {

View File

@ -40,6 +40,7 @@ func primitiveType (name string) *entity.TypeNamed {
func init () {
builtinTypes["Index"] = &entity.TypeWord { }
builtinTypes["Byte"] = &entity.TypeInt { Signed: false, Width: 8 }
builtinTypes["Bool"] = &entity.TypeInt { Signed: false, Width: 8 }
builtinTypes["Rune"] = &entity.TypeInt { Signed: false, Width: 32 }
builtinTypes["String"] = &entity.TypeSlice {
Element: &entity.TypeInt { Signed: false, Width: 8 },

View File

@ -4,15 +4,18 @@ import "testing"
func TestCastErrIntPointer (test *testing.T) {
testStringErr (test,
"cannot convert from *Int to Int", 2, 14,
"cannot convert from *Int to Int", 4, 9,
`
[main]:Int = [~ Int [@ a:Int]]
[main]:Int = {
a:*Int
[~ Int a]
}
`)
}
func TestCastErrIntStruct (test *testing.T) {
testStringErr (test,
"cannot convert from (x:Int y:Int) to Int", 2, 14,
"cannot convert from (x:Int y:Int) to Int", 2, 21,
`
[main]:Int = [~ Int a:(x:Int y:Int)]
`)
@ -20,7 +23,7 @@ testStringErr (test,
func TestCastErrIntArray (test *testing.T) {
testStringErr (test,
"cannot convert from 5:Int to Int", 2, 14,
"cannot convert from 5:Int to Int", 2, 21,
`
[main]:Int = [~ Int a:5:Int]
`)
@ -28,7 +31,7 @@ testStringErr (test,
func TestCastErrIntSlice (test *testing.T) {
testStringErr (test,
"cannot convert from *:Int to Int", 2, 14,
"cannot convert from *:Int to Int", 2, 21,
`
[main]:Int = [~ Int a:*:Int]
`)
@ -36,15 +39,15 @@ testStringErr (test,
func TestCastErrPointerInt (test *testing.T) {
testStringErr (test,
"cannot convert from Int to *Int", 2, 15,
"cannot convert from Int to *Int", 2, 23,
`
[main]:*Int = [~ *Int [@ a:Int]]
[main]:*Int = [~ *Int a:Int]
`)
}
func TestCastErrStructInt (test *testing.T) {
testStringErr (test,
"cannot convert from Int to (x:Int y:Int)", 2, 24,
"cannot convert from Int to (x:Int y:Int)", 2, 41,
`
[main]:(x:Int y:Int) = [~ (x:Int y:Int) a:Int]
`)
@ -52,7 +55,7 @@ testStringErr (test,
func TestCastErrArrayInt (test *testing.T) {
testStringErr (test,
"cannot convert from Int to 5:Int", 2, 13,
"cannot convert from 5:Int to Int", 2, 21,
`
[main]:Int = [~ Int a:5:Int]
`)
@ -60,7 +63,7 @@ testStringErr (test,
func TestCastErrSliceInt (test *testing.T) {
testStringErr (test,
"cannot convert from Int to *:Int", 2, 16,
"cannot convert from Int to *:Int", 2, 25,
`
[main]:*:Int = [~ *:Int a:Int]
`)
@ -71,8 +74,8 @@ testString (test,
`
Bird: ([fly distance:F64] [land])
BlueJay: Int
BlueJay::[fly distance:F64] = { }
BlueJay::[land] = { }
BlueJay.[fly distance:F64] = { }
BlueJay.[land] = { }
IntDerived: Int
[main] = {
a:IntDerived = 5
@ -80,8 +83,7 @@ IntDerived: Int
c:Int [~~ Int [~~ F64 [~~ Byte a]]]
d:(x:Int y:Int) = (x: 1 y: 2)
e:(z:Int a:Int) = [~~ (z:Int a:Int) d]
f:Bird = [@ [~~ BlueJay 0]]
g:*:Int = [~ *:Int h:5:Int]
f:Bird = [~~ BlueJay 0]
}
`)
}

View File

@ -117,6 +117,7 @@ func (this *Tree) analyzeMethodCall (
if err != nil { return nil, err }
method, err := this.analyzeMethodOrBehavior (
call.Pos, source.Declaration.Type(), call.Name)
if err != nil { return nil, err }
// extract signature
var signature *entity.Signature
@ -278,7 +279,7 @@ func (this *Tree) analyzeValueCast (
err = this.canAssign(cast.Pos, into, mode, cast.Type())
if err != nil { return nil, err }
value, err := this.analyzeExpression(cast.Ty, structural, cast.Value)
value, err := this.analyzeExpression(cast.Ty, coerce, cast.Value)
if err != nil { return nil, err }
cast.Value = value
@ -321,7 +322,7 @@ func (this *Tree) analyzeOperation (
wrongArgCount := func () (entity.Expression, error) {
return nil, participle.Errorf (
operation.Pos, "wrong arg count for %v",
operation.Pos, "wrong argument count for %v",
operation.Operator)
}

View File

@ -7,8 +7,8 @@ testStringErr (test,
"Bird.fly already declared at stream0.fspl:3:1", 4, 1,
`
Bird: Int
Bird::[fly] = { }
Bird::[fly distance:Int] = { }
Bird.[fly] = { }
Bird.[fly distance:Int] = { }
`)
}
@ -16,21 +16,21 @@ func TestMethodUnique (test *testing.T) {
testString (test,
`
Bird: Int
Bird::[fly] = { }
Bird::[land] = { }
Bird::[walk distance:Int] = { }
Bird.[fly] = { }
Bird.[land] = { }
Bird.[walk distance:Int] = { }
Bat: Int
Bat::[fly] = { }
Bat.[fly] = { }
[fly] = { }
`)
}
func TestMethodArgumentUniqueErr (test *testing.T) {
testStringErr (test,
"x already listed as argument at stream0.fspl:3:13", 3, 19,
"x already listed as argument at stream0.fspl:3:12", 3, 18,
`
Bird: Int
Bird::[main x:Int x:U8 y:Int] = { }
Bird.[main x:Int x:U8 y:Int] = { }
`)
}
@ -38,6 +38,6 @@ func TestMethodArgumentUnique (test *testing.T) {
testString (test,
`
Bird: Int
Bird::[main x:Int y:U8 z:Int] = { }
Bird.[main x:Int y:U8 z:Int] = { }
`)
}

View File

@ -4,13 +4,13 @@ import "testing"
func TestMethodNameErrMissing (test *testing.T) {
testStringErr (test,
"no method Type::world", 5, 3,
"no method named world defined on this type", 6, 2,
`
Type: Int
Type::[something] = { }
Type.[something] = { }
[main] = {
instance:Type
[instance::world]
instance.[world]
}
`)
}
@ -19,10 +19,10 @@ func TestMethodName (test *testing.T) {
testString (test,
`
Type: Int
Type::[world] = { }
Type.[world] = { }
[main] = {
instance:Type
[instance::world]
instance.[world]
}
`)
}
@ -58,7 +58,7 @@ testString (test,
func TestVariableNameErrFunction (test *testing.T) {
testStringErr (test,
"function example cannot be used as location expression", 4, 2,
"no variable named example", 4, 2,
`
[example] = { }
[main] = {
@ -69,7 +69,7 @@ testStringErr (test,
func TestVariableNameErrMissing (test *testing.T) {
testStringErr (test,
"no variable named example", 4, 2,
"no variable named example", 3, 2,
`
[main] = {
example = 5
@ -112,7 +112,7 @@ testString (test,
func TestFunctionNameErrVar (test *testing.T) {
testStringErr (test,
"cannot call example:Int", 4, 3,
"no function named example", 4, 2,
`
[main] = {
example:Int
@ -123,7 +123,7 @@ testStringErr (test,
func TestFunctionNameErrMissing (test *testing.T) {
testStringErr (test,
"no function named example", 2, 3,
"no function named example", 2, 10,
`
[main] = [example]
`)
@ -139,15 +139,15 @@ testString (test,
func TestInterfaceBehaviorNameErrMissing (test *testing.T) {
testStringErr (test,
"no behavior Bird::swim", 8, 3,
"no behavior or method named swim", 8, 2,
`
Bird: ([fly] [land])
BirdImpl: Int
BirdImpl::[fly] = { }
BirdImpl::[land] = { }
BirdImpl.[fly] = { }
BirdImpl.[land] = { }
[main] = {
bird:Bird = [@impl:BirdImpl]
[bird::swim]
bird:Bird = impl:BirdImpl
bird.[swim]
}
`)
}
@ -157,18 +157,18 @@ testString (test,
`
Bird: ([fly] [land])
BirdImpl: Int
BirdImpl::[fly] = { }
BirdImpl::[land] = { }
BirdImpl.[fly] = { }
BirdImpl.[land] = { }
[main] = {
bird:Bird = [@impl:BirdImpl]
[bird::fly]
bird:Bird = impl:BirdImpl
bird.[fly]
}
`)
}
func TestStructMemberNameErrMissing (test *testing.T) {
testStringErr (test,
"no member Type.world", 5, 2,
"no member instance.world", 5, 2,
`
Type: (something:Int)
[main] = {

View File

@ -4,7 +4,7 @@ import "testing"
func TestOperationModUnderArgCountErr (test *testing.T) {
testStringErr (test,
"wrong argument count for %", 10, 2,
"wrong argument count for %", 2, 10,
`
[main] = [% 2]
`)
@ -12,7 +12,7 @@ testStringErr (test,
func TestOperationModOverArgCountErr (test *testing.T) {
testStringErr (test,
"wrong argument count for %", 10, 2,
"wrong argument count for %", 2, 10,
`
[main] = [% 2 3 1]
`)
@ -20,7 +20,7 @@ testStringErr (test,
func TestOperationLogicalNegationOverArgCountErr (test *testing.T) {
testStringErr (test,
"wrong argument count for !", 10, 2,
"wrong argument count for !", 2, 10,
`
[main] = [! 348 92]
`)
@ -28,7 +28,7 @@ testStringErr (test,
func TestOperationBitwiseNegationOverArgCountErr (test *testing.T) {
testStringErr (test,
"wrong argument count for !!", 10, 2,
"wrong argument count for !!", 2, 10,
`
[main] = [!! 348 92]
`)
@ -36,7 +36,7 @@ testStringErr (test,
func TestOperationBitShiftLeftOverArgCountErr (test *testing.T) {
testStringErr (test,
"wrong argument count for <<", 10, 2,
"wrong argument count for <<", 2, 10,
`
[main] = [<< 348 92 324]
`)
@ -44,7 +44,7 @@ testStringErr (test,
func TestOperationBitShiftRightOverArgCountErr (test *testing.T) {
testStringErr (test,
"wrong argument count for >>", 10, 2,
"wrong argument count for >>", 2, 10,
`
[main] = [>> 348 92 324]
`)

View File

@ -58,6 +58,8 @@ chunks of memory, and to index arrays and such.
### Byte
Byte is defined as the smallest addressable integer. It is unsigned. It is
usually equivalent to U8.
### Bool
Bool is a boolean type. It is equivalent to Byte.
### Rune
Rune is defined as a U32. It represents a single UTF-32 code point.
### String