mirror of
https://github.com/bendtherules/not-a-js-engine.git
synced 2026-08-18 22:01:53 +00:00
Implement string, number literal and completion record
This commit is contained in:
@@ -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';
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { TNumberValue } from './NumberValue';
|
||||
import { TStringValue } from './StringValue';
|
||||
|
||||
export type LanguageType = TNumberValue | TStringValue;
|
||||
@@ -0,0 +1,3 @@
|
||||
export const NumberString = 'number';
|
||||
|
||||
export const StringString = 'string';
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { parse } from 'acorn';
|
||||
|
||||
export function parseScript(content: string) {
|
||||
export function ParseScript(content: string) {
|
||||
return parse(content);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)}"`
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user