Skip to content

Commit

Permalink
Merge pull request #541 from jvalue/540-feature-lowercaseuppercase-op…
Browse files Browse the repository at this point in the history
…erator

add unary operators 'lowercase' and 'uppercase'
  • Loading branch information
TungstnBallon authored Apr 10, 2024
2 parents 23dd62b + a41762e commit 7590227
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 2 deletions.
6 changes: 5 additions & 1 deletion apps/docs/docs/user/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ The following expression is evaluated to the `text` `I love Datypus`: `"I love p
- `matches` for a regex match, e.g., `"A07" matches /^[A-Z0-9]*$/` evaluates to `true`
- `in` for inclusion in an array, e.g., `"a" in ["a", "b", "c"]` evaluates to `true`

#### Text manipulation (unary operators)
- `lowercase` converts all alphabetic characters in a text to lowercase
- `uppercase` converts all alphabetic characters in a text to uppercase

#### Text manipulation (ternary operators)
- `replace [...] with [...]` replaces regex matches in a text with a string

Expand All @@ -80,4 +84,4 @@ The operator supports `text`, `integer` and `decimal` values as operands. The co


### Further reading
For a deeper documentation of how expressions and operators work internally, refer to the [developer docs](../dev/04-guides/04-expressions-and-operators.md).
For a deeper documentation of how expressions and operators work internally, refer to the [developer docs](../dev/04-guides/04-expressions-and-operators.md).
2 changes: 1 addition & 1 deletion libs/language-server/src/grammar/expression.langium
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ PrimaryExpression infers Expression:
| ExpressionLiteral;

UnaryExpression:
operator=('not' | '+' | '-' | 'sqrt' | 'floor' | 'ceil' | 'round') expression=PrimaryExpression;
operator=('not' | '+' | '-' | 'sqrt' | 'floor' | 'ceil' | 'round' | 'lowercase' | 'uppercase') expression=PrimaryExpression;

ExpressionLiteral:
ValueLiteral | FreeVariableLiteral;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: 2024 Friedrich-Alexander-Universitat Erlangen-Nurnberg
//
// SPDX-License-Identifier: AGPL-3.0-only
import { executeDefaultTextToTextExpression } from '../test-utils';

describe('The lowercase operator', () => {
it('should lowercase alphabetic characters successfully', async () => {
const result = await executeDefaultTextToTextExpression(
'lowercase inputValue',
'Hello, World!',
);

expect(result).toEqual('hello, world!');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-FileCopyrightText: 2024 Friedrich-Alexander-Universitat Erlangen-Nurnberg
//
// SPDX-License-Identifier: AGPL-3.0-only

// eslint-disable-next-line import/no-cycle
import { DefaultUnaryOperatorEvaluator } from '../operator-evaluator';
import { STRING_TYPEGUARD } from '../typeguards';

export class LowercaseOperatorEvaluator extends DefaultUnaryOperatorEvaluator<
string,
string
> {
constructor() {
super('lowercase', STRING_TYPEGUARD);
}
override doEvaluate(operandValue: string): string {
return operandValue.toLowerCase();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: 2024 Friedrich-Alexander-Universitat Erlangen-Nurnberg
//
// SPDX-License-Identifier: AGPL-3.0-only
import { executeDefaultTextToTextExpression } from '../test-utils';

describe('The uppercase operator', () => {
it('should uppercase alphabetic characters successfully', async () => {
const result = await executeDefaultTextToTextExpression(
'uppercase inputValue',
'Hello, World!',
);

expect(result).toEqual('HELLO, WORLD!');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-FileCopyrightText: 2024 Friedrich-Alexander-Universitat Erlangen-Nurnberg
//
// SPDX-License-Identifier: AGPL-3.0-only

// eslint-disable-next-line import/no-cycle
import { DefaultUnaryOperatorEvaluator } from '../operator-evaluator';
import { STRING_TYPEGUARD } from '../typeguards';

export class UppercaseOperatorEvaluator extends DefaultUnaryOperatorEvaluator<
string,
string
> {
constructor() {
super('uppercase', STRING_TYPEGUARD);
}
override doEvaluate(operandValue: string): string {
return operandValue.toUpperCase();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { InOperatorEvaluator } from './evaluators/in-operator-evaluator';
import { InequalityOperatorEvaluator } from './evaluators/inequality-operator-evaluator';
import { LessEqualOperatorEvaluator } from './evaluators/less-equal-operator-evaluator';
import { LessThanOperatorEvaluator } from './evaluators/less-than-operator-evaluator';
import { LowercaseOperatorEvaluator } from './evaluators/lowercase-operator-evaluator';
import { MatchesOperatorEvaluator } from './evaluators/matches-operator-evaluator';
import { MinusOperatorEvaluator } from './evaluators/minus-operator-evaluator';
import { ModuloOperatorEvaluator } from './evaluators/modulo-operator-evaluator';
Expand All @@ -35,6 +36,7 @@ import { RootOperatorEvaluator } from './evaluators/root-operator-evaluator';
import { RoundOperatorEvaluator } from './evaluators/round-operator-evaluator';
import { SqrtOperatorEvaluator } from './evaluators/sqrt-operator-evaluator';
import { SubtractionOperatorEvaluator } from './evaluators/subtraction-operator-evaluator';
import { UppercaseOperatorEvaluator } from './evaluators/uppercase-operator-evaluator';
import { XorOperatorEvaluator } from './evaluators/xor-operator-evaluator';
import { type OperatorEvaluator } from './operator-evaluator';
import {
Expand All @@ -60,6 +62,7 @@ import { RelationalOperatorTypeComputer } from './type-computers/relational-oper
import { ReplaceOperatorTypeComputer } from './type-computers/replace-operator-type-computer';
import { SignOperatorTypeComputer } from './type-computers/sign-operator-type-computer';
import { SqrtOperatorTypeComputer } from './type-computers/sqrt-operator-type-computer';
import { StringTransformTypeComputer } from './type-computers/string-transform-type-computer';

export interface OperatorEvaluatorRegistry {
unary: Record<UnaryExpressionOperator, OperatorEvaluator<UnaryExpression>>;
Expand Down Expand Up @@ -87,6 +90,8 @@ export class DefaultOperatorEvaluatorRegistry
floor: new FloorOperatorEvaluator(),
ceil: new CeilOperatorEvaluator(),
round: new RoundOperatorEvaluator(),
lowercase: new LowercaseOperatorEvaluator(),
uppercase: new UppercaseOperatorEvaluator(),
};
binary = {
pow: new PowOperatorEvaluator(),
Expand Down Expand Up @@ -124,6 +129,8 @@ export class DefaultOperatorTypeComputerRegistry
floor: new IntegerConversionOperatorTypeComputer(),
ceil: new IntegerConversionOperatorTypeComputer(),
round: new IntegerConversionOperatorTypeComputer(),
lowercase: new StringTransformTypeComputer(),
uppercase: new StringTransformTypeComputer(),
};
binary = {
pow: new ExponentialOperatorTypeComputer(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: 2024 Friedrich-Alexander-Universitat Erlangen-Nurnberg
//
// SPDX-License-Identifier: AGPL-3.0-only

import { type ValueType } from '../../wrappers/value-type';
// eslint-disable-next-line import/no-cycle
import { PrimitiveValuetypes } from '../../wrappers/value-type/primitive/primitive-value-types';
import { DefaultUnaryOperatorTypeComputer } from '../operator-type-computer';

export class StringTransformTypeComputer extends DefaultUnaryOperatorTypeComputer {
constructor() {
super(PrimitiveValuetypes.Text);
}

override doComputeType(): ValueType {
return PrimitiveValuetypes.Text;
}
}

0 comments on commit 7590227

Please sign in to comment.