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 weak
// structural equivalence // structural equivalence
structural structural
// allow if values can be converted
coerce
// assignment rules are completely ignored and everything is accepted // assignment rules are completely ignored and everything is accepted
force force
) )
@ -28,15 +30,38 @@ func (this *Tree) canAssign (
mode strictness, mode strictness,
source entity.Type, source entity.Type,
) error { ) 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 // short circuit if force is selected
if mode == force { return nil } 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 // do structural equivalence if structural is selected
if mode == structural { if mode == structural {
if this.areStructurallyEquivalent(destination, source) { if this.areStructurallyEquivalent(destination, source) {
return nil return nil
} else { } else {
return participle.Errorf(pos, "expected %v", destination) return fail()
} }
} }
@ -82,7 +107,54 @@ func (this *Tree) canAssign (
*entity.TypeBool: *entity.TypeBool:
if !destination.Equals(source) { 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)) default: panic(fmt.Sprint("BUG: analyzer doesnt know about type ", destination))
@ -133,8 +205,6 @@ func (this *Tree) canAssignInterface (
method)) method))
} }
fmt.Println(signature, behavior)
// check equivalence // check equivalence
if !signature.Equals(behavior) { if !signature.Equals(behavior) {
return participle.Errorf ( return participle.Errorf (

View File

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

View File

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

View File

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

View File

@ -7,8 +7,8 @@ testStringErr (test,
"Bird.fly already declared at stream0.fspl:3:1", 4, 1, "Bird.fly already declared at stream0.fspl:3:1", 4, 1,
` `
Bird: Int Bird: Int
Bird::[fly] = { } Bird.[fly] = { }
Bird::[fly distance:Int] = { } Bird.[fly distance:Int] = { }
`) `)
} }
@ -16,21 +16,21 @@ func TestMethodUnique (test *testing.T) {
testString (test, testString (test,
` `
Bird: Int Bird: Int
Bird::[fly] = { } Bird.[fly] = { }
Bird::[land] = { } Bird.[land] = { }
Bird::[walk distance:Int] = { } Bird.[walk distance:Int] = { }
Bat: Int Bat: Int
Bat::[fly] = { } Bat.[fly] = { }
[fly] = { } [fly] = { }
`) `)
} }
func TestMethodArgumentUniqueErr (test *testing.T) { func TestMethodArgumentUniqueErr (test *testing.T) {
testStringErr (test, 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: 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, testString (test,
` `
Bird: Int 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) { func TestMethodNameErrMissing (test *testing.T) {
testStringErr (test, testStringErr (test,
"no method Type::world", 5, 3, "no method named world defined on this type", 6, 2,
` `
Type: Int Type: Int
Type::[something] = { } Type.[something] = { }
[main] = { [main] = {
instance:Type instance:Type
[instance::world] instance.[world]
} }
`) `)
} }
@ -19,10 +19,10 @@ func TestMethodName (test *testing.T) {
testString (test, testString (test,
` `
Type: Int Type: Int
Type::[world] = { } Type.[world] = { }
[main] = { [main] = {
instance:Type instance:Type
[instance::world] instance.[world]
} }
`) `)
} }
@ -58,7 +58,7 @@ testString (test,
func TestVariableNameErrFunction (test *testing.T) { func TestVariableNameErrFunction (test *testing.T) {
testStringErr (test, testStringErr (test,
"function example cannot be used as location expression", 4, 2, "no variable named example", 4, 2,
` `
[example] = { } [example] = { }
[main] = { [main] = {
@ -69,7 +69,7 @@ testStringErr (test,
func TestVariableNameErrMissing (test *testing.T) { func TestVariableNameErrMissing (test *testing.T) {
testStringErr (test, testStringErr (test,
"no variable named example", 4, 2, "no variable named example", 3, 2,
` `
[main] = { [main] = {
example = 5 example = 5
@ -112,7 +112,7 @@ testString (test,
func TestFunctionNameErrVar (test *testing.T) { func TestFunctionNameErrVar (test *testing.T) {
testStringErr (test, testStringErr (test,
"cannot call example:Int", 4, 3, "no function named example", 4, 2,
` `
[main] = { [main] = {
example:Int example:Int
@ -123,7 +123,7 @@ testStringErr (test,
func TestFunctionNameErrMissing (test *testing.T) { func TestFunctionNameErrMissing (test *testing.T) {
testStringErr (test, testStringErr (test,
"no function named example", 2, 3, "no function named example", 2, 10,
` `
[main] = [example] [main] = [example]
`) `)
@ -139,15 +139,15 @@ testString (test,
func TestInterfaceBehaviorNameErrMissing (test *testing.T) { func TestInterfaceBehaviorNameErrMissing (test *testing.T) {
testStringErr (test, testStringErr (test,
"no behavior Bird::swim", 8, 3, "no behavior or method named swim", 8, 2,
` `
Bird: ([fly] [land]) Bird: ([fly] [land])
BirdImpl: Int BirdImpl: Int
BirdImpl::[fly] = { } BirdImpl.[fly] = { }
BirdImpl::[land] = { } BirdImpl.[land] = { }
[main] = { [main] = {
bird:Bird = [@impl:BirdImpl] bird:Bird = impl:BirdImpl
[bird::swim] bird.[swim]
} }
`) `)
} }
@ -157,18 +157,18 @@ testString (test,
` `
Bird: ([fly] [land]) Bird: ([fly] [land])
BirdImpl: Int BirdImpl: Int
BirdImpl::[fly] = { } BirdImpl.[fly] = { }
BirdImpl::[land] = { } BirdImpl.[land] = { }
[main] = { [main] = {
bird:Bird = [@impl:BirdImpl] bird:Bird = impl:BirdImpl
[bird::fly] bird.[fly]
} }
`) `)
} }
func TestStructMemberNameErrMissing (test *testing.T) { func TestStructMemberNameErrMissing (test *testing.T) {
testStringErr (test, testStringErr (test,
"no member Type.world", 5, 2, "no member instance.world", 5, 2,
` `
Type: (something:Int) Type: (something:Int)
[main] = { [main] = {

View File

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

View File

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