Feature - Support plus binary expression for number and string

This commit is contained in:
2020-08-13 18:06:56 +05:30
parent 066e92d4b5
commit 01cac9f672
7 changed files with 78 additions and 1 deletions
+5
View File
@@ -6,6 +6,7 @@ import {
NumericLiteral,
StringLiteral,
Program,
BinaryExpression,
} from './types';
export function isProgram(node: Node): node is Program {
@@ -27,3 +28,7 @@ export function isNumericLiteral(node: Node): node is NumericLiteral {
export function isStringLiteral(node: Node): node is StringLiteral {
return isLiteral(node) && typeof node.value === 'string';
}
export function isBinaryExpression(node: Node): node is BinaryExpression {
return node.type === TypeStrings.BinaryExpression;
}
+11 -1
View File
@@ -6,6 +6,7 @@ export enum TypeStrings {
Program = 'Program',
ExpressionStatement = 'ExpressionStatement',
Literal = 'Literal',
BinaryExpression = 'BinaryExpression',
}
export interface Program extends Node {
@@ -18,7 +19,8 @@ export interface ExpressionStatement extends Node {
expression: Expression;
}
export type Expression = Literal | Node;
// TODO: Add more possible type of expressions here and remove generic node
export type Expression = Literal | BinaryExpression | Node;
export interface Literal extends Node {
type: TypeStrings.Literal;
@@ -34,3 +36,11 @@ export interface StringLiteral extends Node {
type: TypeStrings.Literal;
value: string;
}
export interface BinaryExpression extends Node {
type: TypeStrings.BinaryExpression;
left: Literal;
right: Literal;
// TODO: Add actual possible operators here
operator: string;
}
+18
View File
@@ -4,11 +4,13 @@ import {
isNumericLiteral,
isStringLiteral,
isProgram,
isBinaryExpression,
} from './acorn-helpers/isType';
import {
NormalCompletion,
CompletionRecord,
v,
} from './internal-types/CompletionRecord';
import { NumberValue } from './language-types/NumberValue';
@@ -30,6 +32,22 @@ export function Evaluate(node: Node): CompletionRecord {
} else if (isStringLiteral(node)) {
// Handle StringLiteral
return NormalCompletion(new StringValue(node.value));
} else if (isBinaryExpression(node)) {
if (node.operator === '+') {
// TODO - Forward completion record for abrupt completions
const leftVal = v(Evaluate(node.left));
const rightVal = v(Evaluate(node.right));
if (leftVal instanceof NumberValue && rightVal instanceof NumberValue) {
return NormalCompletion(
new NumberValue(leftVal.getValue() + rightVal.getValue())
);
}
if (leftVal instanceof StringValue && rightVal instanceof StringValue) {
return NormalCompletion(
new StringValue(leftVal.getValue() + rightVal.getValue())
);
}
}
} else {
// If not handled, throw error
throwUnknownNode(node);
+10
View File
@@ -29,3 +29,13 @@ export class CompletionRecord implements TCompletionRecord {
export function NormalCompletion(value?: TValue) {
return new CompletionRecord('normal', value);
}
export function v(cr: CompletionRecord): LanguageType | undefined {
if (cr[TypeString] === 'normal') {
return cr[ValueString];
}
// TODO: Else, from call site, return same value
return undefined;
}
export class AbruptCompletion extends TypeError {}
+5
View File
@@ -3,6 +3,7 @@ import { NumberString } from './typeNames';
export interface TNumberValue {
type: typeof NumberString;
value: number;
getValue(): number;
}
export class NumberValue implements TNumberValue {
@@ -13,4 +14,8 @@ export class NumberValue implements TNumberValue {
this.type = NumberString;
this.value = value;
}
getValue(): number {
return this.value;
}
}
+5
View File
@@ -3,6 +3,7 @@ import { StringString } from './typeNames';
export interface TStringValue {
type: typeof StringString;
value: string;
getValue(): string;
}
export class StringValue implements TStringValue {
@@ -13,4 +14,8 @@ export class StringValue implements TStringValue {
this.type = StringString;
this.value = value;
}
getValue(): string {
return this.value;
}
}
+24
View File
@@ -22,4 +22,28 @@ describe('evaluate literals', () => {
expect(returnVal).toBeInstanceOf(CompletionRecord);
expect(returnVal[ValueString]?.value).toBe('abc');
});
it('for 10+20', () => {
const node = ParseScript(`10 + 20`);
const returnVal = Evaluate(node);
expect(returnVal).toBeInstanceOf(CompletionRecord);
expect(returnVal[ValueString]?.value).toBe(30);
});
it('for 10+20+30', () => {
const node = ParseScript(`10 + 20 + 30`);
const returnVal = Evaluate(node);
expect(returnVal).toBeInstanceOf(CompletionRecord);
expect(returnVal[ValueString]?.value).toBe(60);
});
it('for "ab"+"cd"', () => {
const node = ParseScript(`"ab"+"cd"`);
const returnVal = Evaluate(node);
expect(returnVal).toBeInstanceOf(CompletionRecord);
expect(returnVal[ValueString]?.value).toBe('abcd');
});
});