Pass all but one test
This commit is contained in:
parent
a2e22d1154
commit
47beb9e41f
@ -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) {
|
||||
|
@ -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 },
|
||||
|
@ -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]
|
||||
}
|
||||
`)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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] = { }
|
||||
`)
|
||||
}
|
||||
|
@ -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] = {
|
||||
|
@ -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]
|
||||
`)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user