Skip to content

Commit

Permalink
refactor(all): Complete interpreter refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasBoda committed Jan 18, 2024
1 parent b4805f3 commit 2f47539
Show file tree
Hide file tree
Showing 8 changed files with 421 additions and 348 deletions.
45 changes: 22 additions & 23 deletions src/interpreter/interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import { Observable, Subject, Subscription, interval, takeWhile } from "rxjs";
import { Symbol, Symbolizer } from "../symbolizer";
import { Lexer, Token } from "../lexer";
import { Parser, ParserValue, Program } from "../parser";
import { Runtime, Environment, FunctionCall, NumberValue, RuntimeAgent, RuntimeOutput, RuntimeValue, ValueType } from "../runtime";
import { Runtime, Environment, FunctionCall, NumberValue, RuntimeAgent, RuntimeOutput, RuntimeValue, ValueType, createGlobalFunction } from "../runtime";
import { Agent, InterpreterConfiguration, InterpreterOutput } from "./model";
import { ErrorModel, ErrorRuntime } from "../utils";
import { createGlobalFunction } from "../runtime/functions/utils";

export class Interpreter {

Expand All @@ -22,6 +21,26 @@ export class Interpreter {

private program?: Program;

// subscribes to interpreter output
public get(sourceCode: string, config: InterpreterConfiguration): Observable<InterpreterOutput> {
this.build(sourceCode, config);
return this.dataSubject.asObservable();
}

// returns current program
public getProgram(): Program {
return this.program!;
}

// sets new program
public setProgram(program: Program): void {
this.program = program;
}

public updateAgentValue(agentIndex: number, propertyIdentifier: string, value: number): void {
this.runtime?.updateAgentValue(agentIndex, propertyIdentifier, value);
}

public build(sourceCode: string, config: InterpreterConfiguration): void {
this.sourceCode = sourceCode;
this.config = config;
Expand All @@ -32,7 +51,7 @@ export class Interpreter {

// generate source code tokens
this.lexer = new Lexer(symbols);
let tokens: Token[] =this.lexer.tokenize();
let tokens: Token[] = this.lexer.tokenize();

// generate source code abstract syntax tree
this.parser = new Parser(tokens);
Expand All @@ -52,22 +71,6 @@ export class Interpreter {
this.reset();
}

// subscribes to interpreter output
public get(sourceCode: string, config: InterpreterConfiguration): Observable<InterpreterOutput> {
this.build(sourceCode, config);
return this.dataSubject.asObservable();
}

// returns current program
public getProgram(): Program {
return this.program!;
}

// sets new program
public setProgram(program: Program): void {
this.program = program;
}

// rebuilds current interpreter step
public rebuild(): void {
this.runtime?.setProgram(this.program!);
Expand Down Expand Up @@ -180,8 +183,4 @@ export class Interpreter {

return heightFunction;
}

public updateAgentValue(agentIndex: number, propertyIdentifier: string, value: number): void {
this.runtime?.updateAgentValue(agentIndex, propertyIdentifier, value);
}
}
81 changes: 52 additions & 29 deletions src/lexer/lexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,21 @@ export class Lexer {
break;
case "<": {
const operator = this.next();
if (this.isNext("=")) operator.value += this.next().value;

if (this.isNext("=")) {
operator.value += this.next().value;
}

this.token(TokenType.RelationalOperator, operator);
break;
}
case ">": {
const operator = this.next();
if (this.isNext("=")) operator.value += this.next().value;

if (this.isNext("=")) {
operator.value += this.next().value;
}

this.token(TokenType.RelationalOperator, operator);
break;
}
Expand Down Expand Up @@ -94,33 +102,12 @@ export class Lexer {
const { position } = this.getNext();

if (this.isNumber()) {
let number = "";
let foundDecimalPoint = false;

while (this.hasNext() && (this.isNumber() || this.isNext("."))) {
if (this.isNext(".")) {
if (foundDecimalPoint) {
throw new ErrorLexer("Number cannot contain more than one decimal point", position);
}

foundDecimalPoint = true;
}

number += this.next().value;
}

this.token(TokenType.Number, { value: number, position });
this.tokenizeNumber(position);
break;
}

if (this.isAlpha()) {
let identifier = "";

while (this.hasNext() && (this.isAlpha() || this.getNext().value === "_")) {
identifier += this.next().value;
}

this.token(this.getIdentifierTokenType(identifier), { value: identifier, position });
this.tokenizeIdentifier(position);
break;
}

Expand All @@ -139,6 +126,35 @@ export class Lexer {
return this.tokens;
}

private tokenizeNumber(position: Position): void {
let number = "";
let foundDecimalPoint = false;

while (this.hasNext() && (this.isNumber() || this.isNext("."))) {
if (this.isNext(".")) {
if (foundDecimalPoint) {
throw new ErrorLexer("Number cannot contain more than one decimal point", position);
}

foundDecimalPoint = true;
}

number += this.next().value;
}

this.token(TokenType.Number, { value: number, position });
}

private tokenizeIdentifier(position: Position): void {
let identifier = "";

while (this.hasNext() && (this.isAlpha() || this.getNext().value === "_")) {
identifier += this.next().value;
}

this.token(this.getKeywordOrIdentifierTokenType(identifier), { value: identifier, position });
}

private hasNext(): boolean {
return this.symbols.length > 0;
}
Expand All @@ -152,7 +168,13 @@ export class Lexer {
}

private next(): Symbol {
return this.symbols.shift() ?? {} as Symbol;
const symbol = this.symbols.shift();

if (!symbol) {
throw new ErrorLexer("Cannot retrieve next token, since it does not exist");
}

return symbol;
}

private token(type: TokenType, symbol = this.next()): void {
Expand All @@ -171,7 +193,7 @@ export class Lexer {
this.token(TokenType.EOF, { value: "EOF", position: eofPosition });
}

private getIdentifierTokenType(identifier: string): TokenType {
private getKeywordOrIdentifierTokenType(identifier: string): TokenType {
const keyword = ReservedKeywords[identifier];
return keyword ? keyword : TokenType.Identifier;
}
Expand All @@ -181,13 +203,14 @@ export class Lexer {
}

private isNumber(): boolean {
const symbol: number = this.getNext().value.charCodeAt(0);
const symbol = this.getNext().value.charCodeAt(0);
const bounds = { lower: "0".charCodeAt(0), upper: "9".charCodeAt(0) };
return symbol >= bounds.lower && symbol <= bounds.upper;
}

private isSkippable(): boolean {
return this.getNext().value === " " || this.getNext().value === "\n" || this.getNext().value === "\t";
const skippableCharacters = [ " ", "\n", "\t" ];
return skippableCharacters.includes(this.getNext().value);
}

private clearTokens(): void {
Expand Down
Loading

0 comments on commit 2f47539

Please sign in to comment.