Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions interpreter/operator_dispatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,13 @@ func (i *interpreter) unaryOverloads(m model.IUnaryExpression) ([]convert.Overlo
Result: i.evalPopulationStdDevQuantity,
},
}, nil
case *model.Tail:
return []convert.Overload[evalUnarySignature]{
{
Operands: []types.IType{&types.List{ElementType: types.Any}},
Result: evalTail,
},
}, nil
default:
return nil, fmt.Errorf("unsupported Unary Expression %v", m.GetName())
}
Expand Down
18 changes: 18 additions & 0 deletions interpreter/operator_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,24 @@ func evalSkip(m model.IBinaryExpression, listObj, indexObj result.Value) (result
return result.New(result.List{Value: list[index:], StaticType: staticType})
}

// Tail(argument List<T>) List<T>
// https://cql.hl7.org/09-b-cqlreference.html#tail
func evalTail(m model.IUnaryExpression, listObj result.Value) (result.Value, error) {
if result.IsNull(listObj) {
return result.New(nil)
}
list, err := result.ToSlice(listObj)
if err != nil {
return result.Value{}, err
}
staticType := listObj.GolangValue().(result.List).StaticType
// If the list is empty, return an empty list.
if len(list) == 0 {
return result.New(result.List{StaticType: staticType})
}
return result.New(result.List{Value: list[1:], StaticType: staticType})
}

// Indexer(argument List<T>, index Integer) T
// [](argument List<T>, index Integer) T
// https://cql.hl7.org/09-b-cqlreference.html#indexer-1
Expand Down
6 changes: 6 additions & 0 deletions model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,9 @@ type CalculateAge struct {
Precision DateTimePrecision
}

// Tail ELM Expression https://cql.hl7.org/09-b-cqlreference.html#tail.
type Tail struct{ *UnaryExpression }

// BinaryExpression is a CQL expression that has two operands. The ELM representation may have
// additional operands (ex BinaryExpressionWithPrecision).
type BinaryExpression struct {
Expand Down Expand Up @@ -1476,5 +1479,8 @@ func (m *Median) GetName() string { return "Median" }
// GetName returns the name of the system operator.
func (s *Skip) GetName() string { return "Skip" }

// GetName returns the name of the system operator.
func (t *Tail) GetName() string { return "Tail" }

// GetName returns the name of the system operator.
func (m *PopulationStdDev) GetName() string { return "PopulationStdDev" }
13 changes: 13 additions & 0 deletions parser/operators.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ func (v *visitor) resolveFunction(libraryName, funcName string, operands []model
case *model.Skip:
listType := resolved.WrappedOperands[0].GetResultType().(*types.List)
t.Expression = model.ResultType(&types.List{ElementType: listType.ElementType})
case *model.Tail:
listType := resolved.WrappedOperands[0].GetResultType().(*types.List)
t.Expression = model.ResultType(&types.List{ElementType: listType.ElementType})
case *model.Union:
listTypeLeft := resolved.WrappedOperands[0].GetResultType().(*types.List)
listTypeRight := resolved.WrappedOperands[1].GetResultType().(*types.List)
Expand Down Expand Up @@ -1646,6 +1649,16 @@ func (p *Parser) loadSystemOperators() error {
}
},
},
{
name: "Tail",
operands: [][]types.IType{
{&types.List{ElementType: types.Any}}},
model: func() model.IExpression {
return &model.Tail{
UnaryExpression: &model.UnaryExpression{},
}
},
},
{
name: "Union",
operands: [][]types.IType{{&types.List{ElementType: types.Any}, &types.List{ElementType: types.Any}}},
Expand Down
10 changes: 10 additions & 0 deletions parser/operators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1304,6 +1304,16 @@ func TestBuiltInFunctions(t *testing.T) {
},
},
},
{
name: "Tail",
cql: "Tail({1, 2, 3})",
want: &model.Tail{
UnaryExpression: &model.UnaryExpression{
Operand: model.NewList([]string{"1", "2", "3"}, types.Integer),
Expression: model.ResultType(&types.List{ElementType: types.Integer}),
},
},
},
{
name: "Union",
cql: "Union({1}, {'hi'})",
Expand Down
87 changes: 87 additions & 0 deletions tests/enginetests/operator_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,93 @@ func TestSkip(t *testing.T) {
}
}

func TestTail(t *testing.T) {
tests := []struct {
name string
cql string
wantModel model.IExpression
wantResult result.Value
wantSourceExpression model.IExpression
wantSourceValues []result.Value
}{
{
name: "Tail({1, 2}) = {2}",
cql: "Tail({1, 2})",
wantModel: &model.Tail{
UnaryExpression: &model.UnaryExpression{
Operand: model.NewList([]string{"1", "2"}, types.Integer),
Expression: model.ResultType(&types.List{ElementType: types.Integer}),
},
},
wantResult: newOrFatal(t, result.List{Value: []result.Value{newOrFatal(t, int32(2))}, StaticType: &types.List{ElementType: types.Integer}}),
wantSourceExpression: &model.Tail{
UnaryExpression: &model.UnaryExpression{
Operand: model.NewList([]string{"1", "2"}, types.Integer),
Expression: model.ResultType(&types.List{ElementType: types.Integer}),
},
},
},
{
name: "Tail({1}) = {}",
cql: "Tail({1})",
wantResult: newOrFatal(t, result.List{Value: []result.Value{}, StaticType: &types.List{ElementType: types.Integer}}),
},
{
name: "Tail(List<Integer>{}) = {}",
cql: "Tail(List<Integer>{})",
wantResult: newOrFatal(t, result.List{Value: []result.Value{}, StaticType: &types.List{ElementType: types.Integer}}),
},
{
name: "Tail(null as List<Integer>) = null",
cql: "Tail(null as List<Integer>)",
wantResult: newOrFatal(t, nil),
},
{
name: "Tail(null as List<Integer>) = null",
cql: "Tail(null as List<Integer>)",
wantResult: newOrFatal(t, nil),
},
{
name: "Tail({@2010, @2011, @2012}) = {@2011, @2012}",
cql: "Tail({@2010, @2011, @2012})",
wantResult: newOrFatal(t, result.List{
Value: []result.Value{
newOrFatal(t, result.Date{Date: time.Date(2011, time.January, 1, 0, 0, 0, 0, defaultEvalTimestamp.Location()), Precision: model.YEAR}),
newOrFatal(t, result.Date{Date: time.Date(2012, time.January, 1, 0, 0, 0, 0, defaultEvalTimestamp.Location()), Precision: model.YEAR}),
},
StaticType: &types.List{ElementType: types.Date},
}),
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
p := newFHIRParser(t)
parsedLibs, err := p.Libraries(context.Background(), wrapInLib(t, tc.cql), parser.Config{})
if err != nil {
t.Fatalf("Parse returned unexpected error: %v", err)
}
if diff := cmp.Diff(tc.wantModel, getTESTRESULTModel(t, parsedLibs)); tc.wantModel != nil && diff != "" {
t.Errorf("Parse diff (-want +got):\n%s", diff)
}

results, err := interpreter.Eval(context.Background(), parsedLibs, defaultInterpreterConfig(t, p))
if err != nil {
t.Fatalf("Eval returned unexpected error: %v", err)
}
gotResult := getTESTRESULTWithSources(t, results)
if diff := cmp.Diff(tc.wantResult, gotResult, protocmp.Transform()); diff != "" {
t.Errorf("Eval returned diff (-want +got)\n%v", diff)
}
if diff := cmp.Diff(tc.wantSourceExpression, gotResult.SourceExpression(), protocmp.Transform()); tc.wantSourceExpression != nil && diff != "" {
t.Errorf("Eval SourceExpression diff (-want +got)\n%v", diff)
}
if diff := cmp.Diff(tc.wantSourceValues, gotResult.SourceValues(), protocmp.Transform()); tc.wantSourceValues != nil && diff != "" {
t.Errorf("Eval SourceValues diff (-want +got)\n%v", diff)
}
})
}
}

func TestIndexerList(t *testing.T) {
tests := []struct {
name string
Expand Down
2 changes: 1 addition & 1 deletion tests/spectests/exclusions/exclusions.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,6 @@ func XMLTestFileExclusionDefinitions() map[string]XMLTestFileExclusions {
"ProperIn",
"ProperlyIncludes",
"ProperlyIncludedIn",
"Tail",
"Take",
"Union",
},
Expand All @@ -369,6 +368,7 @@ func XMLTestFileExclusionDefinitions() map[string]XMLTestFileExclusions {
"EqualNullNull",
// TODO: b/346880550 - These test appear to have incorrect assertions.
"SkipAll",
"TailOneElement",
},
},
"CqlQueryTests.xml": XMLTestFileExclusions{
Expand Down
Loading