From 2e80b8db6ab66afb520248ddae65bb0b4a80493e Mon Sep 17 00:00:00 2001 From: nico-blaser <88314447+nnnnblaser@users.noreply.github.com> Date: Wed, 4 Oct 2023 10:01:53 +0200 Subject: [PATCH 1/6] Add SuperTypeMethod --- ttcn3/types/types.go | 121 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/ttcn3/types/types.go b/ttcn3/types/types.go index 3077d0fe..69de4635 100644 --- a/ttcn3/types/types.go +++ b/ttcn3/types/types.go @@ -435,6 +435,14 @@ func TypeOf(n syntax.Expr) Type { } return nil } + case *syntax.Ident: + // names? + if n, ok := Predefined[n.String()]; ok { + return n + } + if n.String() == "infinity" { + return Predefined["float"] + } case *syntax.BinaryExpr: switch n.Op.Kind() { case syntax.LT, syntax.GT, syntax.LE, syntax.GE, syntax.EQ, syntax.NE, syntax.AND, syntax.OR, syntax.XOR: @@ -448,6 +456,19 @@ func TypeOf(n syntax.Expr) Type { return Predefined["integer"] case syntax.SHL, syntax.SHR, syntax.ROL, syntax.ROR: return TypeOf(n.X) + case syntax.ASSIGN: + // Investigate: Label on the left, omit on the right, Maps + if n.Y.FirstTok().Kind() == syntax.OMIT { + if t := TypeOf(n.X); t != nil { + return t + } else { + return Predefined["boolean"] + } + } + if X, ok := n.X.(*syntax.IndexExpr); ok && X.X == nil && TypeOf(X.Index) != Predefined["integer"] { + return &MapType{From: TypeOf(X.Index), To: TypeOf(n.Y)} + } + return TypeOf(n.Y) } case *syntax.UnaryExpr: switch n.Op.Kind() { @@ -461,3 +482,103 @@ func TypeOf(n syntax.Expr) Type { } return nil } + +func isSuper(type1 Type, type2 Type) Type { + if type1 == Predefined["any"] || type2 == Predefined["any"] { + return Predefined["any"] + } + switch type1 := type1.(type) { + case *PrimitiveType: + if type2, ok := type2.(*PrimitiveType); !ok { + return nil + } else { + if type1.Kind == type2.Kind { + if type1.ValueConstraints == nil { + return type1 + } + if type2.ValueConstraints == nil { + return type2 + } + // ToDo: Add more ConstraintChecks + } + return nil + } + case *ListType: + if type2, ok := type2.(*ListType); !ok { + return nil + } else { + if type1.Kind == type2.Kind { + if type1.ElementType == type2.ElementType { + return type1 + } + if isString(type1.Kind) { + // Check Constraints + return nil + } + // check ElementType (Array RecordOf SetOf) + superElement := isSuper(type1.ElementType, type2.ElementType) + if superElement == type1.ElementType { + return type1 + } + if superElement == type2.ElementType { + return type2 + } + return nil + } + switch type1.Kind { + case Hexstring, Octetstring, Bitstring, SetOf: + return nil + case Charstring: + if type2.Kind == UniversalCharstring { + // check Constraints + return type2 + } + return nil + case UniversalCharstring: + if type2.Kind == Charstring { + // check Constraints + return type1 + } + return nil + case RecordOf: + if type2.Kind == Array { + // check ElementType and Constraints + return type1 + } + return nil + case Array: + if type2.Kind == RecordOf { + // check ElementType and Constraints + return type2 + } + return nil + } + } + case *StructuredType: + if type2, ok := type2.(*StructuredType); !ok { + return nil + } else { + if type1.Kind == type2.Kind && len(type1.Fields) == len(type2.Fields) { + for i, f := range type1.Fields { + if f.Optional == type2.Fields[i].Optional && isSuper(f.Type, type2.Fields[i].Type) == f.Type { + continue + } else { + return nil + } + } + return type1 + } + } + case *MapType: + if type2, ok := type2.(*MapType); !ok || type1.From != type2.From { + return nil + } else { + if superTo := isSuper(type1.To, type2.To); superTo == type1.To { + return type1 + } else if superTo == type2.To { + return type2 + } + } + } + return nil +} From d8a590217abfa54a1bdedc1207048e03e517a707 Mon Sep 17 00:00:00 2001 From: nico-blaser <88314447+nnnnblaser@users.noreply.github.com> Date: Wed, 4 Oct 2023 10:04:10 +0200 Subject: [PATCH 2/6] Add methods to determine general Type of list --- ttcn3/types/types.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ttcn3/types/types.go b/ttcn3/types/types.go index 69de4635..6eedf9eb 100644 --- a/ttcn3/types/types.go +++ b/ttcn3/types/types.go @@ -483,6 +483,34 @@ func TypeOf(n syntax.Expr) Type { return nil } +func mostSpecificCommonTypeOfArray(types ...Type) Type { + if len(types) == 0 { + return Predefined["any"] + } + result := types[0] + if len(types) == 1 || result == Predefined["any"] { + return result + } + for _, v := range types[1:] { + result = mostSpecificCommonTypeOf2(result, v) + if result == Predefined["any"] { + break + } + } + return result +} + +func mostSpecificCommonTypeOf2(type1 Type, type2 Type) Type { + if type1 == type2 { + return type1 + } + if t := isSuper(type1, type2); t != nil { + return t + } + // Is there another Type that the two share? + return Predefined["any"] +} + func isSuper(type1 Type, type2 Type) Type { if type1 == Predefined["any"] || type2 == Predefined["any"] { return Predefined["any"] From 5a19f163d986366259911c01f7757e3ef1b32cde Mon Sep 17 00:00:00 2001 From: nico-blaser <88314447+nnnnblaser@users.noreply.github.com> Date: Wed, 4 Oct 2023 10:04:55 +0200 Subject: [PATCH 3/6] Add CompositeLiterals --- ttcn3/types/types.go | 43 +++++++++++++++++++++++++++++++++++++++ ttcn3/types/types_test.go | 33 +++++++++++++++--------------- 2 files changed, 60 insertions(+), 16 deletions(-) diff --git a/ttcn3/types/types.go b/ttcn3/types/types.go index 6eedf9eb..5a2aaf2f 100644 --- a/ttcn3/types/types.go +++ b/ttcn3/types/types.go @@ -479,6 +479,49 @@ func TypeOf(n syntax.Expr) Type { case syntax.INC, syntax.DEC: return Predefined["integer"] } + case *syntax.ParenExpr: + // different length? + if len(n.List) == 1 { + return TypeOf(n.List[0]) + } + case *syntax.IndexExpr: + if n.X == nil { + return TypeOf(n.Index) + } else { + if X, ok := TypeOf(n.X).(*ListType); ok { + return X.ElementType + } else { + return TypeOf(n.X).(*MapType).From + } + } + case *syntax.CompositeLiteral: + fields := make([]Field, len(n.List)) + typeList := make([]Type, len(n.List)) + isRecord := false + + for i, v := range n.List { + typeList[i] = TypeOf(v) + fields[i].Type = typeList[i] + if v, ok := v.(*syntax.BinaryExpr); ok && v.Op.Kind() == syntax.ASSIGN && v.Y.FirstTok().Kind() == syntax.OMIT { + fields[i].Optional = true + isRecord = true + } else { + fields[i].Optional = false + } + } + if len(fields) == 0 { + return &ListType{Kind: RecordOf} + } + if t := mostSpecificCommonTypeOfArray(typeList...); isRecord || t == Predefined["any"] { + t = &StructuredType{Kind: Record, Fields: fields} + return t + } else { + // Map vs Record of Maps? + if _, ok := t.(*MapType); ok { + return t + } + return &ListType{Kind: RecordOf, ElementType: t} + } } return nil } diff --git a/ttcn3/types/types_test.go b/ttcn3/types/types_test.go index cb43915c..f17aa801 100644 --- a/ttcn3/types/types_test.go +++ b/ttcn3/types/types_test.go @@ -312,14 +312,14 @@ func TestTypeInference(t *testing.T) { skip bool }{ // Identifiers - {skip: true, input: `integer`, expect: `integer`}, - {skip: true, input: `float`, expect: `float`}, - {skip: true, input: `boolean`, expect: `boolean`}, + {input: `integer`, expect: `integer`}, + {input: `float`, expect: `float`}, + {input: `boolean`, expect: `boolean`}, // ValueLiterals {input: `0`, expect: `integer`}, {input: `0.0`, expect: `float`}, - {skip: true, input: `infinity`, expect: `float`}, + {input: `infinity`, expect: `float`}, {input: `not_a_number`, expect: `float`}, {input: `true`, expect: `boolean`}, {input: `false`, expect: `boolean`}, @@ -342,18 +342,19 @@ func TestTypeInference(t *testing.T) { {input: `not true or false`, expect: `boolean`}, {input: `1+2 <= 3`, expect: `boolean`}, - {skip: true, input: `x := ¶{1}`, expect: `record of integer`}, - {skip: true, input: `x := ¶{1,2,3}`, expect: `record of integer`}, - {skip: true, input: `x := ¶{1+2,2,3}`, expect: `record of integer`}, - {skip: true, input: `x := ¶{(1+2),2,(3)}`, expect: `record of integer`}, - {skip: true, input: `x := ¶{{1},{2},{}}`, expect: `record of record of integer`}, - {skip: true, input: `x := ¶{"A",""}`, expect: `record of charstring`}, - {skip: true, input: `x := ¶{"A","Ä"}`, expect: `record of universal charstring`}, - {skip: true, input: `x := ¶{x := 2, y := true}`, expect: `record { integer, boolean }`}, - {skip: true, input: `x := ¶{x := 2, y := omit}`, expect: `record { integer, boolean optional}`}, - {skip: true, input: `x := ¶{integer := 2, float := omit}`, expect: `record { integer, float optional}`}, - {skip: true, input: `x := ¶{[1] := 1, [3] := 2, [2] := 3}`, expect: `record of integer`}, - {skip: true, input: `x := ¶{[1.0] := 1, [3.0] := 2, [2.0] := 3}`, expect: `map from float to integer`}, + {input: `x := ¶{1}`, expect: `record of integer`}, + {input: `x := ¶{1,2,3}`, expect: `record of integer`}, + {input: `x := ¶{1+2,2,3}`, expect: `record of integer`}, + {input: `x := ¶{(1+2),2,(3)}`, expect: `record of integer`}, + {input: `x := ¶{{1},{2},{}}`, expect: `record of record of integer`}, + {input: `x := ¶{"A",""}`, expect: `record of charstring`}, + {input: `x := ¶{"A","Ä"}`, expect: `record of universal charstring`}, + {input: `x := ¶{x := 2, y := true}`, expect: `record {integer, boolean}`}, + {input: `x := ¶{x := 2, y := omit}`, expect: `record {integer, boolean optional}`}, + {input: `x := ¶{integer := 2, float := omit}`, expect: `record {integer, float optional}`}, + {input: `x := ¶{[1] := 1, [3] := 2, [2] := 3}`, expect: `record of integer`}, + {input: `x := ¶{[1.0] := 1, [3.0] := 2, [2.0] := 3}`, expect: `map from float to integer`}, + {input: `x := ¶{["ÄB"] := 1.0, ["CÖ"] := 2.0, ["EÜ"] := 3.0}`, expect: `map from universal charstring to float`}, //{skip: true, input: `x := 2`, expect: `void`}, //{skip: true, input: `mtc == null`, expect: `boolean`}, From 14bb2a9a51694623b97ebfa63b607b2ab20c7515 Mon Sep 17 00:00:00 2001 From: nico-blaser <88314447+nnnnblaser@users.noreply.github.com> Date: Wed, 4 Oct 2023 10:11:23 +0200 Subject: [PATCH 4/6] Wrong Test --- ttcn3/types/types_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ttcn3/types/types_test.go b/ttcn3/types/types_test.go index f17aa801..18467508 100644 --- a/ttcn3/types/types_test.go +++ b/ttcn3/types/types_test.go @@ -346,7 +346,7 @@ func TestTypeInference(t *testing.T) { {input: `x := ¶{1,2,3}`, expect: `record of integer`}, {input: `x := ¶{1+2,2,3}`, expect: `record of integer`}, {input: `x := ¶{(1+2),2,(3)}`, expect: `record of integer`}, - {input: `x := ¶{{1},{2},{}}`, expect: `record of record of integer`}, + {skip: true, input: `x := ¶{{1},{2},{}}`, expect: `record of record of integer`}, {input: `x := ¶{"A",""}`, expect: `record of charstring`}, {input: `x := ¶{"A","Ä"}`, expect: `record of universal charstring`}, {input: `x := ¶{x := 2, y := true}`, expect: `record {integer, boolean}`}, From 56e335a0890d737676c1041d65bc644e7f16a43e Mon Sep 17 00:00:00 2001 From: Matthias Simon <5nord@users.noreply.github.com> Date: Tue, 23 Jul 2024 09:32:03 +0200 Subject: [PATCH 5/6] Update ttcn3/types/types.go --- ttcn3/types/types.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ttcn3/types/types.go b/ttcn3/types/types.go index 5a2aaf2f..bc1d72bc 100644 --- a/ttcn3/types/types.go +++ b/ttcn3/types/types.go @@ -487,8 +487,7 @@ func TypeOf(n syntax.Expr) Type { case *syntax.IndexExpr: if n.X == nil { return TypeOf(n.Index) - } else { - if X, ok := TypeOf(n.X).(*ListType); ok { + } else if X, ok := TypeOf(n.X).(*ListType); ok { return X.ElementType } else { return TypeOf(n.X).(*MapType).From From d4bdd0b538d253703e62842e2c08ccf7aca36055 Mon Sep 17 00:00:00 2001 From: Matthias Simon <5nord@users.noreply.github.com> Date: Tue, 23 Jul 2024 09:32:21 +0200 Subject: [PATCH 6/6] Update ttcn3/types/types.go --- ttcn3/types/types.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ttcn3/types/types.go b/ttcn3/types/types.go index bc1d72bc..750321ae 100644 --- a/ttcn3/types/types.go +++ b/ttcn3/types/types.go @@ -514,11 +514,10 @@ func TypeOf(n syntax.Expr) Type { if t := mostSpecificCommonTypeOfArray(typeList...); isRecord || t == Predefined["any"] { t = &StructuredType{Kind: Record, Fields: fields} return t - } else { - // Map vs Record of Maps? - if _, ok := t.(*MapType); ok { + // Map vs Record of Maps? + } else if _, ok := t.(*MapType); ok { return t - } + } else { return &ListType{Kind: RecordOf, ElementType: t} } }