Implement string, number literal and completion record

This commit is contained in:
2020-08-13 12:22:09 +05:30
parent e4423fa1b5
commit cb24c79a58
10 changed files with 182 additions and 1 deletions
+29
View File
@@ -0,0 +1,29 @@
import {
Node,
ExpressionStatement,
TypeStrings,
Literal,
NumericLiteral,
StringLiteral,
Program,
} from './types';
export function isProgram(node: Node): node is Program {
return node.type === TypeStrings.Program;
}
export function isExpressionStatement(node: Node): node is ExpressionStatement {
return node.type === TypeStrings.ExpressionStatement;
}
export function isLiteral(node: Node): node is Literal {
return node.type === TypeStrings.Literal;
}
export function isNumericLiteral(node: Node): node is NumericLiteral {
return isLiteral(node) && typeof node.value === 'number';
}
export function isStringLiteral(node: Node): node is StringLiteral {
return isLiteral(node) && typeof node.value === 'string';
}
+36
View File
@@ -0,0 +1,36 @@
import { Node as AcornNode } from 'acorn';
export type Node = AcornNode;
export enum TypeStrings {
Program = 'Program',
ExpressionStatement = 'ExpressionStatement',
Literal = 'Literal',
}
export interface Program extends Node {
type: TypeStrings.Program;
body: Node[];
}
export interface ExpressionStatement extends Node {
type: TypeStrings.ExpressionStatement;
expression: Expression;
}
export type Expression = Literal | Node;
export interface Literal extends Node {
type: TypeStrings.Literal;
value: string | boolean | null | number | RegExp;
}
export interface NumericLiteral extends Node {
type: TypeStrings.Literal;
value: number;
}
export interface StringLiteral extends Node {
type: TypeStrings.Literal;
value: string;
}
+34
View File
@@ -0,0 +1,34 @@
import { Node } from './acorn-helpers/types';
import {
isExpressionStatement,
isNumericLiteral,
isStringLiteral,
isProgram,
} from './acorn-helpers/isType';
import {
NormalCompletion,
CompletionRecord,
} from './internal-types/CompletionRecord';
import { NumberValue } from './language-types/NumberValue';
import { StringValue } from './language-types/StringValue';
import { throwUnknownNode } from './throwUnknownNode';
export function Evaluate(node: Node): CompletionRecord {
if (isProgram(node)) {
const completions = node.body.map(tmp => Evaluate(tmp));
return completions[completions.length - 1];
} else if (isExpressionStatement(node)) {
return Evaluate(node.expression);
} else if (isNumericLiteral(node)) {
return NormalCompletion(new NumberValue(node.value));
} else if (isStringLiteral(node)) {
return NormalCompletion(new StringValue(node.value));
} else {
throwUnknownNode(node);
}
return NormalCompletion();
}
+31
View File
@@ -0,0 +1,31 @@
import { LanguageType } from '../language-types/allTypes';
export const TypeString = '[[Type]]';
export const ValueString = '[[Value]]';
export const TargetString = '[[Target]]';
export type TType = 'normal' | 'break' | 'continue' | 'return' | 'throw';
export type TValue = LanguageType | undefined;
export type TTarget = string | undefined;
export interface TCompletionRecord {
[TypeString]: TType;
[ValueString]: TValue;
[TargetString]: TTarget;
}
export class CompletionRecord implements TCompletionRecord {
[TypeString]: TType;
[ValueString]: TValue;
[TargetString]: TTarget;
constructor(type: TType, value?: TValue, target?: TTarget) {
this[TypeString] = type;
this[ValueString] = value;
this[TargetString] = target;
}
}
export function NormalCompletion(value?: TValue) {
return new CompletionRecord('normal', value);
}
+16
View File
@@ -0,0 +1,16 @@
import { NumberString } from './typeNames';
export interface TNumberValue {
type: typeof NumberString;
value: number;
}
export class NumberValue implements TNumberValue {
type: typeof NumberString;
value: number;
constructor(value: number) {
this.type = NumberString;
this.value = value;
}
}
+16
View File
@@ -0,0 +1,16 @@
import { StringString } from './typeNames';
export interface TStringValue {
type: typeof StringString;
value: string;
}
export class StringValue implements TStringValue {
type: typeof StringString;
value: string;
constructor(value: string) {
this.type = StringString;
this.value = value;
}
}
+4
View File
@@ -0,0 +1,4 @@
import { TNumberValue } from './NumberValue';
import { TStringValue } from './StringValue';
export type LanguageType = TNumberValue | TStringValue;
+3
View File
@@ -0,0 +1,3 @@
export const NumberString = 'number';
export const StringString = 'string';
+1 -1
View File
@@ -1,5 +1,5 @@
import { parse } from 'acorn';
export function parseScript(content: string) {
export function ParseScript(content: string) {
return parse(content);
}
+12
View File
@@ -0,0 +1,12 @@
import { Node } from './acorn-helpers/types';
class NotImplementedError extends TypeError {}
export function throwUnknownNode(node: Node) {
throw new NotImplementedError(
`Unknown type: ${node.type} with text "${node.sourceFile?.slice(
node.start,
node.end
)}"`
);
}