Rename directory "engines" to "languages"

This commit is contained in:
Nilay Majorwar
2022-01-30 20:47:33 +05:30
parent 0bf7c0de3a
commit e3be5a8a83
82 changed files with 27 additions and 21 deletions

View File

@ -0,0 +1,25 @@
import { executeProgram, readTestProgram } from "../../test-utils";
import ChefRuntime from "../runtime";
/** Absolute path to directory of sample programs */
const DIRNAME = __dirname + "/samples";
describe("Test programs", () => {
test("Hello World Souffle", async () => {
const code = readTestProgram(DIRNAME, "hello-world-souffle");
const result = await executeProgram(new ChefRuntime(), code);
expect(result.output).toBe("Hello world!");
});
test("Fibonacci Du Fromage", async () => {
const code = readTestProgram(DIRNAME, "fibonacci-fromage");
const result = await executeProgram(new ChefRuntime(), code, "10");
expect(result.output).toBe(" 1 1 2 3 5 8 13 21 34 55");
});
test("Hello World Cake with Chocolate Sauce", async () => {
const code = readTestProgram(DIRNAME, "hello-world-cake");
const result = await executeProgram(new ChefRuntime(), code);
expect(result.output).toBe("Hello world!");
});
});

View File

@ -0,0 +1,389 @@
import { ChefOperation, StackItemType } from "../types";
import { JumpAddressPlaceholder } from "../parser/constants";
import { parseIngredientItem, parseMethodStep } from "../parser/core";
/** Test the result of parsing an ingredient definition string */
const testIngredientItem = (
str: string,
name: string,
value: number | undefined,
type: StackItemType
) => {
const result = parseIngredientItem(str);
expect(result.name).toBe(name);
expect(result.item.value).toBe(value);
expect(result.item.type).toBe(type);
};
/** Test the result of parsing a method operation string */
const testMethodOp = (str: string, op: ChefOperation) => {
const result = parseMethodStep(str);
expect(result).toEqual(op);
};
describe("Parsing ingredient definitions", () => {
test("dry ingredients", () => {
testIngredientItem("10 g sugar", "sugar", 10, "dry");
testIngredientItem("2 kg dry almonds", "dry almonds", 2, "dry");
testIngredientItem("1 pinch chilli powder", "chilli powder", 1, "dry");
testIngredientItem("3 pinches chilli powder", "chilli powder", 3, "dry");
});
test("liquid ingredients", () => {
testIngredientItem("10 ml essence", "essence", 10, "liquid");
testIngredientItem("2 l milk", "milk", 2, "liquid");
testIngredientItem("1 dash oil", "oil", 1, "liquid");
testIngredientItem("3 dashes oil", "oil", 3, "liquid");
});
test("dry-or-liquid ingredients", () => {
testIngredientItem("1 cup flour", "flour", 1, "unknown");
testIngredientItem("2 cups flour", "flour", 2, "unknown");
testIngredientItem("1 teaspoon salt", "salt", 1, "unknown");
testIngredientItem("2 teaspoons salt", "salt", 2, "unknown");
testIngredientItem("1 tablespoon ketchup", "ketchup", 1, "unknown");
testIngredientItem("2 tablespoons ketchup", "ketchup", 2, "unknown");
});
});
describe("Parsing method instructions", () => {
test("Take `ing` from refrigerator", () => {
testMethodOp("Take chilli powder from refrigerator", {
code: "STDIN",
ing: "chilli powder",
});
});
test("Put `ing` into [the] [`nth`] mixing bowl", () => {
testMethodOp("Put dry ice into the mixing bowl", {
code: "PUSH",
ing: "dry ice",
bowlId: 1,
});
testMethodOp("Put dry ice into the 21nd mixing bowl", {
code: "PUSH",
ing: "dry ice",
bowlId: 21,
});
testMethodOp("Put dry ice into mixing bowl", {
code: "PUSH",
ing: "dry ice",
bowlId: 1,
});
testMethodOp("Put dry ice into 21nd mixing bowl", {
code: "PUSH",
ing: "dry ice",
bowlId: 21,
});
});
test("Fold `ing` into [the] [`nth`] mixing bowl", () => {
testMethodOp("Fold dry ice into the mixing bowl", {
code: "POP",
ing: "dry ice",
bowlId: 1,
});
testMethodOp("Fold dry ice into the 21nd mixing bowl", {
code: "POP",
ing: "dry ice",
bowlId: 21,
});
testMethodOp("Fold dry ice into mixing bowl", {
code: "POP",
ing: "dry ice",
bowlId: 1,
});
testMethodOp("Fold dry ice into 21nd mixing bowl", {
code: "POP",
ing: "dry ice",
bowlId: 21,
});
});
test("Add `ing` [to [the] [`nth`] mixing bowl]", () => {
testMethodOp("Add black salt", {
code: "ADD",
ing: "black salt",
bowlId: 1,
});
testMethodOp("Add black salt to the mixing bowl", {
code: "ADD",
ing: "black salt",
bowlId: 1,
});
testMethodOp("Add black salt to the 100th mixing bowl", {
code: "ADD",
ing: "black salt",
bowlId: 100,
});
testMethodOp("Add black salt to mixing bowl", {
code: "ADD",
ing: "black salt",
bowlId: 1,
});
testMethodOp("Add black salt to 100th mixing bowl", {
code: "ADD",
ing: "black salt",
bowlId: 100,
});
});
test("Remove `ing` [from [the] [`nth`] mixing bowl]", () => {
testMethodOp("Remove black salt", {
code: "SUBTRACT",
ing: "black salt",
bowlId: 1,
});
testMethodOp("Remove black salt from the mixing bowl", {
code: "SUBTRACT",
ing: "black salt",
bowlId: 1,
});
testMethodOp("Remove black salt from the 100th mixing bowl", {
code: "SUBTRACT",
ing: "black salt",
bowlId: 100,
});
testMethodOp("Remove black salt from mixing bowl", {
code: "SUBTRACT",
ing: "black salt",
bowlId: 1,
});
testMethodOp("Remove black salt from 100th mixing bowl", {
code: "SUBTRACT",
ing: "black salt",
bowlId: 100,
});
});
test("Combine `ing` [into [the] [`nth`] mixing bowl]", () => {
testMethodOp("Combine black salt", {
code: "MULTIPLY",
ing: "black salt",
bowlId: 1,
});
testMethodOp("Combine black salt into the mixing bowl", {
code: "MULTIPLY",
ing: "black salt",
bowlId: 1,
});
testMethodOp("Combine black salt into the 2nd mixing bowl", {
code: "MULTIPLY",
ing: "black salt",
bowlId: 2,
});
testMethodOp("Combine black salt into mixing bowl", {
code: "MULTIPLY",
ing: "black salt",
bowlId: 1,
});
testMethodOp("Combine black salt into 2nd mixing bowl", {
code: "MULTIPLY",
ing: "black salt",
bowlId: 2,
});
});
test("Divide `ing` [into [the] [`nth`] mixing bowl]", () => {
testMethodOp("Divide black salt", {
code: "DIVIDE",
ing: "black salt",
bowlId: 1,
});
testMethodOp("Divide black salt into the mixing bowl", {
code: "DIVIDE",
ing: "black salt",
bowlId: 1,
});
testMethodOp("Divide black salt into the 23rd mixing bowl", {
code: "DIVIDE",
ing: "black salt",
bowlId: 23,
});
testMethodOp("Divide black salt into mixing bowl", {
code: "DIVIDE",
ing: "black salt",
bowlId: 1,
});
testMethodOp("Divide black salt into 23rd mixing bowl", {
code: "DIVIDE",
ing: "black salt",
bowlId: 23,
});
});
test("Add dry ingredients [to [the] [`nth`] mixing bowl]", () => {
testMethodOp("Add dry ingredients", {
code: "ADD-DRY",
bowlId: 1,
});
testMethodOp("Add dry ingredients to mixing bowl", {
code: "ADD-DRY",
bowlId: 1,
});
testMethodOp("Add dry ingredients to 100th mixing bowl", {
code: "ADD-DRY",
bowlId: 100,
});
testMethodOp("Add dry ingredients to mixing bowl", {
code: "ADD-DRY",
bowlId: 1,
});
testMethodOp("Add dry ingredients to 100th mixing bowl", {
code: "ADD-DRY",
bowlId: 100,
});
});
test("Liquefy `ingredient`", () => {
testMethodOp("Liquefy nitrogen gas", {
code: "LIQ-ING",
ing: "nitrogen gas",
});
testMethodOp("Liquefy the nitrogen gas", {
code: "LIQ-ING",
ing: "nitrogen gas",
});
testMethodOp("Liquefy themed leaves", {
code: "LIQ-ING",
ing: "themed leaves",
});
});
test("Liquefy [the] contents of the [`nth`] mixing bowl", () => {
testMethodOp("Liquefy the contents of the mixing bowl", {
code: "LIQ-BOWL",
bowlId: 1,
});
testMethodOp("Liquefy the contents of the 22nd mixing bowl", {
code: "LIQ-BOWL",
bowlId: 22,
});
testMethodOp("Liquefy contents of the mixing bowl", {
code: "LIQ-BOWL",
bowlId: 1,
});
testMethodOp("Liquefy contents of the 22nd mixing bowl", {
code: "LIQ-BOWL",
bowlId: 22,
});
});
test("Stir [the [`nth`] mixing bowl] for `num` minutes", () => {
testMethodOp("Stir for 5 minutes", {
code: "ROLL-BOWL",
bowlId: 1,
num: 5,
});
testMethodOp("Stir the mixing bowl for 22 minutes", {
code: "ROLL-BOWL",
bowlId: 1,
num: 22,
});
testMethodOp("Stir the 3rd mixing bowl for 0 minutes", {
code: "ROLL-BOWL",
bowlId: 3,
num: 0,
});
});
test("Stir `ing` into the [`nth`] mixing bowl", () => {
testMethodOp("Stir dry ice into the mixing bowl", {
code: "ROLL-ING",
bowlId: 1,
ing: "dry ice",
});
testMethodOp("Stir dry ice into the 2nd mixing bowl", {
code: "ROLL-ING",
bowlId: 2,
ing: "dry ice",
});
});
test("Mix [the [`nth`] mixing bowl] well", () => {
testMethodOp("Mix well", { code: "RANDOM", bowlId: 1 });
testMethodOp("Mix the mixing bowl well", { code: "RANDOM", bowlId: 1 });
testMethodOp("Mix the 21st mixing bowl well", {
code: "RANDOM",
bowlId: 21,
});
});
test("Clean [the] [`nth`] mixing bowl", () => {
testMethodOp("Clean the mixing bowl", { code: "CLEAR", bowlId: 1 });
testMethodOp("Clean the 21st mixing bowl", { code: "CLEAR", bowlId: 21 });
testMethodOp("Clean mixing bowl", { code: "CLEAR", bowlId: 1 });
testMethodOp("Clean 21st mixing bowl", { code: "CLEAR", bowlId: 21 });
});
test("Pour contents of the [`nth`] mixing bowl into the [`pth`] baking dish", () => {
testMethodOp("Pour contents of the mixing bowl into the baking dish", {
code: "COPY",
bowlId: 1,
dishId: 1,
});
testMethodOp(
"Pour contents of the 2nd mixing bowl into the 100th baking dish",
{
code: "COPY",
bowlId: 2,
dishId: 100,
}
);
testMethodOp(
"Pour contents of the mixing bowl into the 100th baking dish",
{
code: "COPY",
bowlId: 1,
dishId: 100,
}
);
testMethodOp("Pour contents of the 2nd mixing bowl into the baking dish", {
code: "COPY",
bowlId: 2,
dishId: 1,
});
});
test("`Verb` the `ingredient`", () => {
testMethodOp("Bake the dough", {
code: "LOOP-OPEN",
verb: "bake",
ing: "dough",
closer: JumpAddressPlaceholder,
});
});
test("`Verb` [the `ingredient`] until `verbed`", () => {
testMethodOp("Destroy until bake", {
code: "LOOP-CLOSE",
verb: "bake",
opener: JumpAddressPlaceholder,
});
testMethodOp("Destroy the tomato ketchup until bake", {
code: "LOOP-CLOSE",
verb: "bake",
ing: "tomato ketchup",
opener: JumpAddressPlaceholder,
});
});
test("Set aside", () => {
testMethodOp("Set aside", {
code: "LOOP-BREAK",
closer: JumpAddressPlaceholder,
});
});
test("Serve with `auxiliary-recipe`", () => {
testMethodOp("Serve with chocolate sauce", {
code: "FNCALL",
recipe: "chocolate sauce",
});
});
test("Refrigerate [for `num` hours]", () => {
testMethodOp("Refrigerate", { code: "END" });
testMethodOp("Refrigerate for 2 hours", { code: "END", num: 2 });
});
});

View File

@ -0,0 +1,159 @@
import { readTestProgram } from "../../test-utils";
import { parseProgram } from "../parser";
import { LoopCloseOp, LoopOpenOp } from "../types";
/** Absolute path to directory of sample programs */
const DIRNAME = __dirname + "/samples";
describe("Parsing entire programs", () => {
test("Hello World Souffle", () => {
const code = readTestProgram(DIRNAME, "hello-world-souffle");
const program = parseProgram(code);
expect(program.auxes).toEqual({});
expect(program.main.name).toBe("Hello World Souffle");
expect(program.main.serves).toEqual({ line: 19, num: 1 });
// Lightly check list of ingredients
const ingredients = program.main.ingredients;
expect(Object.keys(ingredients).length).toBe(9);
expect(ingredients["haricot beans"].type).toBe("dry");
expect(ingredients["haricot beans"].value).toBe(72);
expect(ingredients["eggs"].type).toBe("unknown");
expect(ingredients["eggs"].value).toBe(101);
expect(ingredients["oil"].type).toBe("unknown");
expect(ingredients["oil"].value).toBe(111);
expect(ingredients["water"].type).toBe("liquid");
expect(ingredients["water"].value).toBe(119);
// Check method operations
const method = program.main.method;
expect(method.length).toBe(14);
expect(method.slice(0, 12).every((m) => m.op.code === "PUSH")).toBe(true);
expect(method[12].op.code).toBe("LIQ-BOWL");
expect(method[12].location.line).toBe(17);
expect([403, 404]).toContain(method[12].location.charRange?.start);
expect([439, 440]).toContain(method[12].location.charRange?.end);
expect(method[13].op.code).toBe("COPY");
expect(method[13].location.line).toBe(17);
});
test("Fibonacci Du Fromage", () => {
const code = readTestProgram(DIRNAME, "fibonacci-fromage");
const program = parseProgram(code);
expect(program.main.name).toBe("Fibonacci Du Fromage");
expect(program.main.serves).toEqual({ line: 30, num: 1 });
// ====== MAIN RECIPE =======
// Check the list of ingredients
const mainIngredients = program.main.ingredients;
expect(Object.keys(mainIngredients).length).toBe(2);
expect(mainIngredients["numbers"]).toEqual({ type: "dry", value: 5 });
expect(mainIngredients["cheese"]).toEqual({ type: "dry", value: 1 });
// Check the method instructions
const mainMethod = program.main.method;
expect(mainMethod.length).toBe(19);
expect(mainMethod[0].op.code).toBe("STDIN");
expect(mainMethod[0].location.line).toBe(10);
expect(mainMethod[0].location.charRange?.start).toBe(0);
expect(mainMethod[0].location.charRange?.end).toBe(30);
expect(mainMethod[18].op.code).toBe("COPY");
expect(mainMethod[18].location.line).toBe(28);
expect(mainMethod[18].location.charRange?.start).toBe(0);
expect(mainMethod[18].location.charRange?.end).toBe(57);
// Check loop jump addresses in method
const mainOpener1 = mainMethod[8].op as LoopOpenOp;
const mainCloser1 = mainMethod[10].op as LoopCloseOp;
expect(mainOpener1.closer).toBe(10);
expect(mainCloser1.opener).toBe(8);
const mainOpener2 = mainMethod[14].op as LoopOpenOp;
const mainCloser2 = mainMethod[17].op as LoopCloseOp;
expect(mainOpener2.closer).toBe(17);
expect(mainCloser2.opener).toBe(14);
// ====== AUXILIARY RECIPE =========
expect(Object.keys(program.auxes)).toEqual(["salt and pepper"]);
const auxIngredients = program.auxes["salt and pepper"].ingredients;
// Check the list of ingredients
expect(Object.keys(auxIngredients).length).toBe(2);
expect(auxIngredients["salt"]).toEqual({ type: "dry", value: 1 });
expect(auxIngredients["pepper"]).toEqual({ type: "dry", value: 1 });
// Check the method instructions
const auxMethod = program.auxes["salt and pepper"].method;
expect(auxMethod.length).toBe(5);
expect(auxMethod[0].op.code).toBe("POP");
expect(auxMethod[0].location.line).toBe(39);
expect(auxMethod[0].location.charRange?.start).toBe(0);
expect(auxMethod[0].location.charRange?.end).toBe(26);
expect(auxMethod[4].op.code).toBe("ADD");
expect(auxMethod[4].location.line).toBe(43);
expect(auxMethod[4].location.charRange?.start).toBe(0);
expect(auxMethod[4].location.charRange?.end).toBe(10);
});
test("Hello World Cake with Chocolate Sauce", () => {
const code = readTestProgram(DIRNAME, "hello-world-cake");
const program = parseProgram(code);
expect(program.main.name).toBe("Hello World Cake with Chocolate sauce");
expect(program.main.serves).toBeUndefined();
// ====== MAIN RECIPE =======
// Lightly check the list of ingredients
const mainIngredients = program.main.ingredients;
expect(Object.keys(mainIngredients).length).toBe(9);
expect(mainIngredients["butter"]).toEqual({ type: "dry", value: 100 });
expect(mainIngredients["baking powder"]).toEqual({ type: "dry", value: 2 });
expect(mainIngredients["cake mixture"]).toEqual({ type: "dry", value: 0 });
// Check the method instructions
const mainMethod = program.main.method;
expect(mainMethod.length).toBe(15);
expect(mainMethod[0].op.code).toBe("PUSH");
expect(mainMethod[0].location.line).toBe(27);
expect(mainMethod[0].location.charRange?.start).toBe(0);
expect(mainMethod[0].location.charRange?.end).toBe(40);
expect(mainMethod[14].op.code).toBe("FNCALL");
expect(mainMethod[14].location.line).toBe(41);
expect(mainMethod[14].location.charRange?.start).toBe(0);
expect(mainMethod[14].location.charRange?.end).toBe(26);
// Check loop jump addresses in method
const mainOpener = mainMethod[12].op as LoopOpenOp;
const mainCloser = mainMethod[13].op as LoopCloseOp;
expect(mainOpener.closer).toBe(13);
expect(mainCloser.opener).toBe(12);
// ====== AUXILIARY RECIPE =========
expect(Object.keys(program.auxes)).toEqual(["chocolate sauce"]);
const auxIngredients = program.auxes["chocolate sauce"].ingredients;
// Check the list of ingredients
expect(Object.keys(auxIngredients).length).toBe(5);
expect(auxIngredients["sugar"]).toEqual({ type: "dry", value: 111 });
expect(auxIngredients["heated double cream"]).toEqual({
type: "liquid",
value: 108,
});
// Check the method instructions
const auxMethod = program.auxes["chocolate sauce"].method;
expect(auxMethod.length).toBe(13);
expect(auxMethod[0].op.code).toBe("CLEAR");
expect(auxMethod[0].location.line).toBe(53);
expect(auxMethod[0].location.charRange?.start).toBe(0);
expect(auxMethod[0].location.charRange?.end).toBe(21);
expect(auxMethod[12].op.code).toBe("END");
expect(auxMethod[12].location.line).toBe(65);
expect(auxMethod[12].location.charRange?.start).toBe(0);
expect(auxMethod[12].location.charRange?.end).toBe(22);
// Check loop jump addresses in method
const auxOpener = auxMethod[4].op as LoopOpenOp;
const auxCloser = auxMethod[5].op as LoopCloseOp;
expect(auxOpener.closer).toBe(5);
expect(auxCloser.opener).toBe(4);
});
});

View File

@ -0,0 +1,44 @@
Fibonacci Du Fromage.
==== Source: https://github.com/joostrijneveld/Chef-Interpreter/blob/master/ChefInterpreter/FibonacciDuFromage ====
An improvement on the Fibonacci with Caramel Sauce recipe. Much less for the sweettooths, much more correct.
Ingredients.
5 g numbers
1 g cheese
Method.
Take numbers from refrigerator.
Put cheese into mixing bowl.
Put cheese into mixing bowl.
Put numbers into 2nd mixing bowl.
Remove cheese from 2nd mixing bowl.
Remove cheese from 2nd mixing bowl.
Fold numbers into 2nd mixing bowl.
Put numbers into 2nd mixing bowl.
Calculate the numbers.
Serve with salt and pepper.
Ponder the numbers until calculate.
Add cheese to 2nd mixing bowl.
Add cheese to 2nd mixing bowl.
Fold numbers into 2nd mixing bowl.
Move the numbers.
Fold cheese into mixing bowl.
Put cheese into 2nd mixing bowl.
Transfer the numbers until move.
Pour contents of the 2nd mixing bowl into the baking dish.
Serves 1.
salt and pepper.
Ingredients.
1 g salt
1 g pepper
Method.
Fold salt into mixing bowl.
Fold pepper into mixing bowl.
Clean mixing bowl.
Put salt into mixing bowl.
Add pepper.

View File

@ -0,0 +1,66 @@
Hello World Cake with Chocolate sauce.
==== Source: Mike Worth, http://www.mike-worth.com/2013/03/31/baking-a-hello-world-cake/ ====
This prints hello world, while being tastier than Hello World Souffle. The main
chef makes a " world!" cake, which he puts in the baking dish. When he gets the
sous chef to make the "Hello" chocolate sauce, it gets put into the baking dish
and then the whole thing is printed when he refrigerates the sauce. When
actually cooking, I'm interpreting the chocolate sauce baking dish to be
separate from the cake one and Liquify to mean either melt or blend depending on
context.
Ingredients.
33 g chocolate chips
100 g butter
54 ml double cream
2 pinches baking powder
114 g sugar
111 ml beaten eggs
119 g flour
32 g cocoa powder
0 g cake mixture
Cooking time: 25 minutes.
Pre-heat oven to 180 degrees Celsius.
Method.
Put chocolate chips into the mixing bowl.
Put butter into the mixing bowl.
Put sugar into the mixing bowl.
Put beaten eggs into the mixing bowl.
Put flour into the mixing bowl.
Put baking powder into the mixing bowl.
Put cocoa powder into the mixing bowl.
Stir the mixing bowl for 1 minute.
Combine double cream into the mixing bowl.
Stir the mixing bowl for 4 minutes.
Liquefy the contents of the mixing bowl.
Pour contents of the mixing bowl into the baking dish.
bake the cake mixture.
Wait until bake.
Serve with chocolate sauce.
chocolate sauce.
Ingredients.
111 g sugar
108 ml hot water
108 ml heated double cream
101 g dark chocolate
72 g milk chocolate
Method.
Clean the mixing bowl.
Put sugar into the mixing bowl.
Put hot water into the mixing bowl.
Put heated double cream into the mixing bowl.
dissolve the sugar.
agitate the sugar until dissolve.
Liquefy the dark chocolate.
Put dark chocolate into the mixing bowl.
Liquefy the milk chocolate.
Put milk chocolate into the mixing bowl.
Liquefy contents of the mixing bowl.
Pour contents of the mixing bowl into the baking dish.
Refrigerate for 1 hour.

View File

@ -0,0 +1,20 @@
Hello World Souffle.
==== Source: David Morgan-Mar, https://www.dangermouse.net/esoteric/chef_hello.html ====
This recipe prints the immortal words "Hello world!", in a basically brute force way. It also makes a lot of food for one person.
Ingredients.
72 g haricot beans
101 eggs
108 g lard
111 cups oil
32 zucchinis
119 ml water
114 g red salmon
100 g dijon mustard
33 potatoes
Method.
Put potatoes into the mixing bowl. Put dijon mustard into the mixing bowl. Put lard into the mixing bowl. Put red salmon into the mixing bowl. Put oil into the mixing bowl. Put water into the mixing bowl. Put zucchinis into the mixing bowl. Put oil into the mixing bowl. Put lard into the mixing bowl. Put lard into the mixing bowl. Put eggs into the mixing bowl. Put haricot beans into the mixing bowl. Liquefy contents of the mixing bowl. Pour contents of the mixing bowl into the baking dish.
Serves 1.