Skip to content

Commit

Permalink
Add support for Ln() functional operator.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 646639682
  • Loading branch information
evan-gordon authored and copybara-github committed Jun 25, 2024
1 parent da5fcd6 commit 44f0ed8
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 1 deletion.
16 changes: 16 additions & 0 deletions interpreter/operator_arithmetic.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,22 @@ func evalFloor(_ model.IUnaryExpression, obj result.Value) (result.Value, error)
return result.New(int32(math.Floor(val)))
}

// Ln(argument Decimal) Decimal
// https://cql.hl7.org/09-b-cqlreference.html#ln
func evalLn(_ model.IUnaryExpression, obj result.Value) (result.Value, error) {
if result.IsNull(obj) {
return result.New(nil)
}
val, err := result.ToFloat64(obj)
if err != nil {
return result.Value{}, err
}
if val <= 0 {
return result.New(nil)
}
return result.New(math.Log(val))
}

// op(left Integer, right Integer) Integer
// https://cql.hl7.org/09-b-cqlreference.html#add
// https://cql.hl7.org/09-b-cqlreference.html#subtract
Expand Down
7 changes: 7 additions & 0 deletions interpreter/operator_dispatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,13 @@ func (i *interpreter) unaryOverloads(m model.IUnaryExpression) ([]convert.Overlo
Result: evalFloor,
},
}, nil
case *model.Ln:
return []convert.Overload[evalUnarySignature]{
{
Operands: []types.IType{types.Decimal},
Result: evalLn,
},
}, nil
case *model.Exists:
return []convert.Overload[evalUnarySignature]{
{
Expand Down
6 changes: 6 additions & 0 deletions model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,9 @@ type Ceiling struct{ *UnaryExpression }
// Floor is https://cql.hl7.org/04-logicalspecification.html#floor.
type Floor struct{ *UnaryExpression }

// Ln is https://cql.hl7.org/04-logicalspecification.html#ln.
type Ln struct{ *UnaryExpression }

// SingletonFrom is https://cql.hl7.org/04-logicalspecification.html#singletonfrom.
type SingletonFrom struct{ *UnaryExpression }

Expand Down Expand Up @@ -1129,6 +1132,9 @@ func (a *Ceiling) GetName() string { return "Ceiling" }
// GetName returns the name of the system operator.
func (a *Floor) GetName() string { return "Floor" }

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

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

Expand Down
11 changes: 11 additions & 0 deletions parser/operators.go
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,17 @@ func (p *Parser) loadSystemOperators() error {
}
},
},
{
name: "Ln",
operands: [][]types.IType{{types.Decimal}},
model: func() model.IExpression {
return &model.Ln{
UnaryExpression: &model.UnaryExpression{
Expression: model.ResultType(types.Decimal),
},
}
},
},
{
name: "Negate",
operands: [][]types.IType{{types.Integer}},
Expand Down
10 changes: 10 additions & 0 deletions parser/operators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,16 @@ func TestBuiltInFunctions(t *testing.T) {
},
},
},
{
name: "Arithmetic Ln",
cql: "Ln(1.0)",
want: &model.Ln{
UnaryExpression: &model.UnaryExpression{
Operand: model.NewLiteral("1.0", types.Decimal),
Expression: model.ResultType(types.Decimal),
},
},
},
{
name: "Arithmetic Addition",
cql: "Add(1, 2)",
Expand Down
78 changes: 78 additions & 0 deletions tests/enginetests/operator_arithmetic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,84 @@ func TestFloor(t *testing.T) {
}
}

func TestLn(t *testing.T) {
tests := []struct {
name string
cql string
wantModel model.IExpression
wantResult result.Value
}{
{
name: "Decimal",
cql: "Ln(1.0)",
wantModel: &model.Ln{
UnaryExpression: &model.UnaryExpression{
Operand: model.NewLiteral("1.0", types.Decimal),
Expression: model.ResultType(types.Decimal),
},
},
wantResult: newOrFatal(t, 0.0),
},
{
name: "Negative",
cql: "Ln(-2.1)",
wantResult: newOrFatal(t, nil),
},
{
name: "Zero",
cql: "Ln(0.0)",
wantResult: newOrFatal(t, nil),
},
{
name: "Ten",
cql: "Ln(10.0)",
wantResult: newOrFatal(t, 2.302585092994046),
},
{
name: "Integer",
cql: "Ln(1)",
wantResult: newOrFatal(t, 0.0),
},
{
name: "Minimum Integer",
cql: "Ln(-2147483648)",
wantResult: newOrFatal(t, nil),
},
{
name: "Maximum Integer",
cql: "Ln(2147483647.0)",
wantResult: newOrFatal(t, 21.487562596892644),
},
{
name: "Null",
cql: "Ln(null as Decimal)",
wantResult: newOrFatal(t, nil),
},
}

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)
}

if diff := cmp.Diff(tc.wantResult, getTESTRESULT(t, results), protocmp.Transform()); diff != "" {
t.Errorf("Eval diff (-want +got)\n%v", diff)
}
})
}
}

func TestAdd(t *testing.T) {
tests := []struct {
name string
Expand Down
3 changes: 2 additions & 1 deletion tests/spectests/exclusions/exclusions.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ func XMLTestFileExclusionDefinitions() map[string]XMLTestFileExclusions {
"HighBoundary",
"Log",
"LowBoundary",
"Ln",
"Precision",
"Round",
},
Expand All @@ -64,6 +63,8 @@ func XMLTestFileExclusionDefinitions() map[string]XMLTestFileExclusions {
"Divide103",
"Multiply1CMBy2CM",
"Power2DToNeg2DEquivalence",
"Ln1000", // Require Round support.
"Ln1000D", // Require Round support.
// TODO: b/342061606 - Unit conversion is not supported.
"Divide1Q1",
"Divide10Q5I",
Expand Down

0 comments on commit 44f0ed8

Please sign in to comment.