Replace sample language with deadfish

This commit is contained in:
Nilay Majorwar
2021-12-18 18:16:22 +05:30
parent bb9e85f422
commit 3ace388d90
8 changed files with 161 additions and 141 deletions

View File

@ -0,0 +1,21 @@
# Brainfuck
## Allowed symbols
- `>`: Move the pointer to the right
- `<`: Move the pointer to the left
- `+`: Increment the memory cell at the pointer
- `-`: Decrement the memory cell at the pointer
- `.`: Output the character signified by the cell at the pointer
- `,`: Input a character and store it in the cell at the pointer
- `[`: Jump past the matching `]` if the cell at the pointer is 0
- `]`: Jump back to the matching `[` if the cell at the pointer is nonzero
## Memory specifications
> These parameters will be configurable when engine configuration is added to the project
- For Turing-completeness, the number of cells is kept unbounded.
- Cell size is 8 bits, and allows values in the range `[-128, 127]`.
- Value `10` is designated for newlines.
- The value `0` is returned on reaching `EOF`.

View File

@ -0,0 +1,45 @@
import { MonacoTokensProvider } from "../types";
export type DFRS = {
value: number;
};
export enum DF_OP {
INCR = "i",
DECR = "d",
SQ = "s",
OUT = "o",
}
/** A single element of the program's AST */
export type DFAstStep = {
instr: DF_OP;
location: { line: number; char: number };
};
/** Sample program printing "Hello world" */
export const sampleProgram = [
"iisiiiisiiiiiiiio",
"iiiiiiiiiiiiiiiiiiiiiiiiiiiiio",
"iiiiiiioo",
"iiio",
"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddo",
"dddddddddddddddddddddsddo",
"ddddddddo",
"iiio",
"ddddddo",
"ddddddddo",
].join("\n");
/** Tokens provider */
export const editorTokensProvider: MonacoTokensProvider = {
tokenizer: {
root: [
[/i/, "orange"],
[/d/, "red"],
[/s/, "blue"],
[/o/, "green"],
],
},
defaultToken: "comment",
};

View File

@ -0,0 +1,87 @@
import { setupWorker } from "../setup-worker";
import { DocumentRange, LanguageEngine, StepExecutionResult } from "../types";
import { DFAstStep, DFRS, DF_OP } from "./constants";
// Default values for internal states
// Factories are used to create new objects on reset
const DEFAULT_AST = (): DFAstStep[] => [];
const DEFAULT_PC = -1;
const DEFAULT_VALUE = 0;
// Instruction characters
const OP_CHARS = Object.values(DF_OP);
class DeadfishLanguageEngine implements LanguageEngine<DFRS> {
private _ast: DFAstStep[] = DEFAULT_AST();
private _value: number = DEFAULT_VALUE;
private _pc: number = DEFAULT_PC;
resetState() {
this._ast = DEFAULT_AST();
this._value = DEFAULT_VALUE;
this._pc = DEFAULT_PC;
}
prepare(code: string, _input: string) {
this._ast = this.parseCode(code);
}
executeStep(): StepExecutionResult<DFRS> {
// Execute and update program counter
let output: string | undefined = undefined;
if (this._pc !== -1) {
const astStep = this._ast[this._pc];
output = this.processOp(astStep.instr);
}
this._pc += 1;
// Prepare location of next step
let nextStepLocation: DocumentRange | null = null;
if (this._pc < this._ast.length) {
const { line, char } = this._ast[this._pc].location;
const charRange = { start: char, end: char + 1 };
nextStepLocation = { line, charRange };
}
// Prepare and return execution result
const rendererState = { value: this._value };
return { rendererState, nextStepLocation, output };
}
private parseCode(code: string) {
const ast: DFAstStep[] = [];
// For each line...
code.split("\n").forEach((line, lIdx) => {
// For each character of this line...
line.split("").forEach((char, cIdx) => {
if (OP_CHARS.includes(char as DF_OP)) {
ast.push({
instr: char as DF_OP,
location: { line: lIdx + 1, char: cIdx + 1 },
});
}
});
});
return ast;
}
/**
* Process the given instruction and return string to push to output if any.
*
* @param instr Instruction to apply
* @returns String to append to output, if any
*/
private processOp(instr: DF_OP): string | undefined {
if (instr === DF_OP.INCR) ++this._value;
else if (instr === DF_OP.DECR) --this._value;
else if (instr === DF_OP.SQ) this._value = this._value * this._value;
else if (instr === DF_OP.OUT) return this._value.toString();
else throw new Error("Invalid instruction");
if (this._value === -1 || this._value === 256) this._value = 0;
}
}
setupWorker(new DeadfishLanguageEngine());

11
engines/deadfish/index.ts Normal file
View File

@ -0,0 +1,11 @@
import { Renderer } from "./renderer";
import { LanguageProvider } from "../types";
import { DFRS, sampleProgram, editorTokensProvider } from "./constants";
const provider: LanguageProvider<DFRS> = {
Renderer,
sampleProgram,
editorTokensProvider,
};
export default provider;

View File

@ -0,0 +1,24 @@
import { RendererProps } from "../types";
import { DFRS } from "./constants";
const styles = {
container: {
width: "100%",
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center",
},
text: {
fontSize: "4em",
},
};
export const Renderer = ({ state }: RendererProps<DFRS>) => {
const value = state == null ? 0 : state.value;
return (
<div style={styles.container}>
<h1 style={styles.text}>{value}</h1>
</div>
);
};