Skip to content

Commit

Permalink
[Feat]: add comparison operators
Browse files Browse the repository at this point in the history
  • Loading branch information
snewcomer committed Apr 13, 2021
1 parent be501f0 commit 155e30b
Show file tree
Hide file tree
Showing 12 changed files with 440 additions and 2 deletions.
1 change: 0 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
"tryExtensions": [".js", ".ts", ".d.ts", ".json"]
}
},
"ignorePatterns": ["dist", "ts-dist", "node_modules", "tmp"],
"rules": {
// disabled because we still have a few commented tests
"qunit/no-commented-tests": "off",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { CurriedType } from '@glimmer/interfaces';

import { keywords } from './impl';
import { comparisonKeyword } from './utils/comparison';
import { curryKeyword } from './utils/curry';
import { getDynamicVarKeyword } from './utils/dynamic-vars';
import { equalKeyword, notEqualKeyword } from './utils/equality';
Expand All @@ -15,6 +16,10 @@ export const CALL_KEYWORDS = keywords('Call')
.kw('log', logKeyword)
.kw('eq', equalKeyword, { strictOnly: true })
.kw('neq', notEqualKeyword, { strictOnly: true })
.kw('lt', comparisonKeyword('lt'))
.kw('lte', comparisonKeyword('lte'))
.kw('gt', comparisonKeyword('gt'))
.kw('gte', comparisonKeyword('gte'))
.kw('if', ifUnlessInlineKeyword('if'))
.kw('unless', ifUnlessInlineKeyword('unless'))
.kw('component', curryKeyword(CurriedType.Component))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { ASTv2, generateSyntaxError } from '@glimmer/syntax';

import { Err, Ok, Result } from '../../../../shared/result';
import * as mir from '../../../2-encoding/mir';
import { NormalizationState } from '../../context';
import { VISIT_EXPRS } from '../../visitors/expressions';
import { GenericKeywordNode, KeywordDelegate } from '../impl';

function assertComparisonKeyword(type: string) {
return (
node: GenericKeywordNode
): Result<{ lOperand: ASTv2.ExpressionNode; rOperand: ASTv2.ExpressionNode }> => {
let {
args: { named, positional },
} = node;

if (named && !named.isEmpty()) {
return Err(generateSyntaxError(`(${type}) does not take any named arguments`, node.loc));
}

if (positional.size > 2) {
return Err(generateSyntaxError(`(${type}) can receive a maximum of 2 arguments`, node.loc));
}

let lOperand = positional?.nth(0);
if (!lOperand) {
return Err(
generateSyntaxError(
`(${type}) must receive 2 arguments - a left and right comparison values. Received no arguments.`,
node.loc
)
);
}

let rOperand = positional?.nth(1);
if (!rOperand) {
return Err(
generateSyntaxError(
`(${type}) must receive 2 arguments - a left and right comparison values. Received 1 argument`,
node.loc
)
);
}

return Ok({ lOperand, rOperand });
};
}

function translateComparisonKeyword(type: string) {
return (
{ node, state }: { node: ASTv2.CallExpression; state: NormalizationState },
{ lOperand, rOperand }: { lOperand: ASTv2.ExpressionNode; rOperand: ASTv2.ExpressionNode }
): Result<mir.Less | mir.LessEqual | mir.Greater | mir.GreaterEqual> => {
let lOperandResult = VISIT_EXPRS.visit(lOperand, state);
let rOperandResult = VISIT_EXPRS.visit(rOperand, state);
return Result.all(lOperandResult, rOperandResult).mapOk(([lOperand, rOperand]) => {
// TODO: consider typeing this.
if (type === 'lt') {
return new mir.Less({ loc: node.loc, lOperand, rOperand });
} else if (type === 'lte') {
return new mir.LessEqual({ loc: node.loc, lOperand, rOperand });
} else if (type === 'gt') {
return new mir.Greater({ loc: node.loc, lOperand, rOperand });
} else {
return new mir.GreaterEqual({ loc: node.loc, lOperand, rOperand });
}
});
};
}

export function comparisonKeyword(
type: string
): KeywordDelegate<
ASTv2.CallExpression | ASTv2.AppendContent,
{
lOperand: ASTv2.ExpressionNode;
rOperand: ASTv2.ExpressionNode;
},
mir.Less | mir.LessEqual | mir.Greater | mir.GreaterEqual
> {
return {
assert: assertComparisonKeyword(type),
translate: translateComparisonKeyword(type),
};
}
24 changes: 24 additions & 0 deletions packages/@glimmer/compiler/lib/passes/2-encoding/expressions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ export class ExpressionEncoder {
return this.Equal(expr);
case 'NotEqual':
return this.NotEqual(expr);
case 'Less':
return this.Less(expr);
case 'LessEqual':
return this.LessEqual(expr);
case 'Greater':
return this.Greater(expr);
case 'GreaterEqual':
return this.GreaterEqual(expr);
}
}

Expand Down Expand Up @@ -174,6 +182,22 @@ export class ExpressionEncoder {
NotEqual({ positional }: mir.NotEqual): WireFormat.Expressions.NotEqual {
return [SexpOpcodes.NotEqual, this.Positional(positional)];
}

Less({ lOperand, rOperand }: mir.Less): WireFormat.Expressions.Less {
return [SexpOpcodes.Less, EXPR.expr(lOperand), EXPR.expr(rOperand)];
}

LessEqual({ lOperand, rOperand }: mir.LessEqual): WireFormat.Expressions.LessEqual {
return [SexpOpcodes.LessEqual, EXPR.expr(lOperand), EXPR.expr(rOperand)];
}

Greater({ lOperand, rOperand }: mir.Greater): WireFormat.Expressions.Greater {
return [SexpOpcodes.Greater, EXPR.expr(lOperand), EXPR.expr(rOperand)];
}

GreaterEqual({ lOperand, rOperand }: mir.GreaterEqual): WireFormat.Expressions.GreaterEqual {
return [SexpOpcodes.GreaterEqual, EXPR.expr(lOperand), EXPR.expr(rOperand)];
}
}

export const EXPR = new ExpressionEncoder();
26 changes: 25 additions & 1 deletion packages/@glimmer/compiler/lib/passes/2-encoding/mir.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,26 @@ export class NotEqual extends node('NotEqual').fields<{
positional: Positional;
}>() {}

export class Less extends node('Less').fields<{
lOperand: ExpressionNode;
rOperand: ExpressionNode;
}>() {}

export class LessEqual extends node('LessEqual').fields<{
lOperand: ExpressionNode;
rOperand: ExpressionNode;
}>() {}

export class Greater extends node('Greater').fields<{
lOperand: ExpressionNode;
rOperand: ExpressionNode;
}>() {}

export class GreaterEqual extends node('GreaterEqual').fields<{
lOperand: ExpressionNode;
rOperand: ExpressionNode;
}>() {}

export class InvokeComponent extends node('InvokeComponent').fields<{
definition: ExpressionNode;
args: Args;
Expand Down Expand Up @@ -224,7 +244,11 @@ export type ExpressionNode =
| GetDynamicVar
| Log
| Equal
| NotEqual;
| NotEqual
| Less
| LessEqual
| Greater
| GreaterEqual;

export type ElementParameter = StaticAttr | DynamicAttr | Modifier | SplatAttr;

Expand Down
12 changes: 12 additions & 0 deletions packages/@glimmer/compiler/lib/wire-format-debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,18 @@ export default class WireFormatDebugger {

case Op.NotEqual:
return ['neq', this.formatParams(opcode[1])];

case Op.Less:
return ['lt'];

case Op.LessEqual:
return ['lte'];

case Op.Greater:
return ['gt'];

case Op.GreaterEqual:
return ['gte'];
}
} else {
return opcode;
Expand Down
Loading

0 comments on commit 155e30b

Please sign in to comment.