Skip to content

Commit 23ff906

Browse files
committed
almost done, all tests pass and have coverage, now need to implement inputs
1 parent 411bc36 commit 23ff906

File tree

6 files changed

+236
-26
lines changed

6 files changed

+236
-26
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"test": "test"
1111
},
1212
"scripts": {
13-
"test": "c8 node --test test/**/*.test.js"
13+
"test": "c8 node --test test/generator.test.js"
1414
},
1515
"repository": {
1616
"type": "git",

src/generator.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { voidType, numberType, stringType, functionType, standardLibrary } from "./core.js";
2-
31
export default function generate(program) {
42
const inputCode = [];
53
let inputIndex = 0;
@@ -33,8 +31,7 @@ export default function generate(program) {
3331
const timestep = p.globalRange?.[0]?.timestep?.[0];
3432
const start = range ? gen(range.start) : 1;
3533
const end = range ? gen(range.end[0]) : 5;
36-
const step = timestep ? gen(timestep.value) :
37-
start <= end ? 1 : -1;
34+
const step = timestep ? gen(timestep.value) : 1;
3835
inputCode.push(`
3936
import { createInterface } from "node:readline/promises";
4037
import { stdin as input, stdout as output } from "node:process";
@@ -195,7 +192,7 @@ export default function generate(program) {
195192
if (e.right) {
196193
const left = gen(e.left);
197194
const right = gen(e.right);
198-
return `(${left} ${e.op || "*"} ${right})`;
195+
return `(${left} ${e.op} ${right})`;
199196
}
200197
return gen(e.left);
201198
},

src/optimizer.js

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,34 +75,35 @@ const optimizers = {
7575
if (e.op === '^' && e.right.kind === 'num' && e.right.value === 0) {
7676
return e.left;
7777
}
78-
return e;
7978
},
8079

8180
ShiftExpr(e) {
82-
e.left = optimize(e.left);
83-
e.right = optimize(e.right);
84-
if (e.left.kind === 'num' && e.right.kind === 'num') {
85-
let result;
86-
switch (e.op) {
87-
case '<<': result = e.left.value << e.right.value; break;
88-
case '>>': result = e.left.value >> e.right.value; break;
81+
if (e.op) {
82+
e.left = optimize(e.left);
83+
e.right = optimize(e.right);
84+
if (e.left.kind === 'num' && e.right.kind === 'num') {
85+
let result;
86+
switch (e.op) {
87+
case '<<': result = e.left.value << e.right.value; break;
88+
case '>>': result = e.left.value >> e.right.value; break;
89+
}
90+
return core.num(result);
8991
}
90-
return core.num(result);
91-
}
92-
if (e.right.kind === 'num' && e.right.value === 0) {
93-
return e.left;
92+
if (e.right.kind === 'num' && e.right.value === 0) {
93+
return e.left;
94+
}
95+
return e;
9496
}
95-
return e;
9697
},
9798

9899
AddExpr(e) {
99100
e.left = optimize(e.left);
100101
e.right = optimize(e.right);
101102
if (e.left.kind === 'num' && e.right.kind === 'num') {
102103
const result = e.op === '+'
103-
? e.left.value + e.right.value
104-
: e.left.value - e.right.value;
105-
return core.num(result);
104+
? e.left.value + e.right.value
105+
: e.left.value - e.right.value;
106+
return core.num(result);
106107
}
107108
if (e.op === '+') {
108109
if (e.left.kind === 'num' && e.left.value === 0) return e.right;

test/analyzer.test.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ const semanticChecks = [
5252
["global range with negative integer time step", "`1..10` t-2t\n"],
5353
["global range with float time step", "`1..10` t2.5t\n"],
5454
["global range with character step", "`'a'..'z'`\n"],
55-
["function group", "f(x)=x\ng(x)=x\n{f(x)+g(x)}.step()"],
5655
["input statement with prompt", 'f(x)=input("Hello")'],
5756
["using the function parameter", "f(x)=x*3+x"],
5857
["identifiers", "f(x)=x"],

test/generator.test.js

Lines changed: 216 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1040,7 +1040,222 @@ const fixtures = [
10401040
funktionPrint(x_2.values.slice(0, 7));
10411041
rl.close()
10421042
`)
1043-
}
1043+
},
1044+
{
1045+
name: "reverse range step",
1046+
source:
1047+
`\`5..1\` t1t
1048+
print(1)`,
1049+
expected: dedent(`
1050+
import { createInterface } from "node:readline/promises";
1051+
import { stdin as input, stdout as output } from "node:process";
1052+
const rl = createInterface({ input, output });
1053+
1054+
function generateRange(start = 5, end = 1, step = 1) {
1055+
if (end < start) step *= -1;
1056+
return {
1057+
start,
1058+
end,
1059+
step
1060+
};
1061+
}
1062+
1063+
function initializeMutableRange(timestepRange = generateRange()) {
1064+
return {
1065+
timestepRange,
1066+
values: [],
1067+
index: -1,
1068+
size: 0
1069+
};
1070+
}
1071+
1072+
function funktionPrint(value) {
1073+
if (Array.isArray(value)) {
1074+
console.log(value.join('\\n'));
1075+
}
1076+
else if (typeof value === "object") {
1077+
console.log(value.values.join('\\n'));
1078+
}
1079+
else {
1080+
console.log(value);
1081+
}
1082+
}
1083+
1084+
function applyFunction(gen, iterations, f) {
1085+
let currentVal = gen.timestepRange.start + gen.timestepRange.step * (gen.index + 1);
1086+
if (gen.size === 0) {
1087+
gen.size++;
1088+
gen.index++;
1089+
const result = f(currentVal);
1090+
gen.values.push(Array.isArray(result) ? result.join(' ') : result);
1091+
currentVal += gen.timestepRange.step;
1092+
}
1093+
if (gen.timestepRange.step > 0) {
1094+
while (currentVal <= gen.timestepRange.end && iterations > 0) {
1095+
gen.size++;
1096+
gen.index++;
1097+
const result = f(currentVal);
1098+
gen.values.push(Array.isArray(result) ? result.join(' ') : result);
1099+
currentVal += gen.timestepRange.step;
1100+
iterations--;
1101+
}
1102+
} else {
1103+
while (currentVal >= gen.timestepRange.end && iterations > 0) {
1104+
gen.size++;
1105+
gen.index++;
1106+
const result = f(currentVal);
1107+
gen.values.push(Array.isArray(result) ? result.join(' ') : result);
1108+
currentVal += gen.timestepRange.step;
1109+
iterations--;
1110+
}
1111+
}
1112+
}
1113+
funktionPrint(1);
1114+
rl.close()
1115+
`)
1116+
},
1117+
{
1118+
name: "equality operators",
1119+
source: `print(? 1 == 1 => "yes" : "no")`,
1120+
expected: dedent(`
1121+
import { createInterface } from "node:readline/promises";
1122+
import { stdin as input, stdout as output } from "node:process";
1123+
const rl = createInterface({ input, output });
1124+
1125+
function generateRange(start = 1, end = 5, step = 1) {
1126+
if (end < start) step *= -1;
1127+
return {
1128+
start,
1129+
end,
1130+
step
1131+
};
1132+
}
1133+
1134+
function initializeMutableRange(timestepRange = generateRange()) {
1135+
return {
1136+
timestepRange,
1137+
values: [],
1138+
index: -1,
1139+
size: 0
1140+
};
1141+
}
1142+
1143+
function funktionPrint(value) {
1144+
if (Array.isArray(value)) {
1145+
console.log(value.join('\\n'));
1146+
}
1147+
else if (typeof value === "object") {
1148+
console.log(value.values.join('\\n'));
1149+
}
1150+
else {
1151+
console.log(value);
1152+
}
1153+
}
1154+
1155+
function applyFunction(gen, iterations, f) {
1156+
let currentVal = gen.timestepRange.start + gen.timestepRange.step * (gen.index + 1);
1157+
if (gen.size === 0) {
1158+
gen.size++;
1159+
gen.index++;
1160+
const result = f(currentVal);
1161+
gen.values.push(Array.isArray(result) ? result.join(' ') : result);
1162+
currentVal += gen.timestepRange.step;
1163+
}
1164+
if (gen.timestepRange.step > 0) {
1165+
while (currentVal <= gen.timestepRange.end && iterations > 0) {
1166+
gen.size++;
1167+
gen.index++;
1168+
const result = f(currentVal);
1169+
gen.values.push(Array.isArray(result) ? result.join(' ') : result);
1170+
currentVal += gen.timestepRange.step;
1171+
iterations--;
1172+
}
1173+
} else {
1174+
while (currentVal >= gen.timestepRange.end && iterations > 0) {
1175+
gen.size++;
1176+
gen.index++;
1177+
const result = f(currentVal);
1178+
gen.values.push(Array.isArray(result) ? result.join(' ') : result);
1179+
currentVal += gen.timestepRange.step;
1180+
iterations--;
1181+
}
1182+
}
1183+
}
1184+
funktionPrint(( 1 === 1 ? "yes" : "no"));
1185+
rl.close()
1186+
`)
1187+
},
1188+
{
1189+
name: "inequality operator",
1190+
source: `print(? 1 != 2 => "yes" : "no")`,
1191+
expected: dedent(`
1192+
import { createInterface } from "node:readline/promises";
1193+
import { stdin as input, stdout as output } from "node:process";
1194+
const rl = createInterface({ input, output });
1195+
1196+
function generateRange(start = 1, end = 5, step = 1) {
1197+
if (end < start) step *= -1;
1198+
return {
1199+
start,
1200+
end,
1201+
step
1202+
};
1203+
}
1204+
1205+
function initializeMutableRange(timestepRange = generateRange()) {
1206+
return {
1207+
timestepRange,
1208+
values: [],
1209+
index: -1,
1210+
size: 0
1211+
};
1212+
}
1213+
1214+
function funktionPrint(value) {
1215+
if (Array.isArray(value)) {
1216+
console.log(value.join('\\n'));
1217+
}
1218+
else if (typeof value === "object") {
1219+
console.log(value.values.join('\\n'));
1220+
}
1221+
else {
1222+
console.log(value);
1223+
}
1224+
}
1225+
1226+
function applyFunction(gen, iterations, f) {
1227+
let currentVal = gen.timestepRange.start + gen.timestepRange.step * (gen.index + 1);
1228+
if (gen.size === 0) {
1229+
gen.size++;
1230+
gen.index++;
1231+
const result = f(currentVal);
1232+
gen.values.push(Array.isArray(result) ? result.join(' ') : result);
1233+
currentVal += gen.timestepRange.step;
1234+
}
1235+
if (gen.timestepRange.step > 0) {
1236+
while (currentVal <= gen.timestepRange.end && iterations > 0) {
1237+
gen.size++;
1238+
gen.index++;
1239+
const result = f(currentVal);
1240+
gen.values.push(Array.isArray(result) ? result.join(' ') : result);
1241+
currentVal += gen.timestepRange.step;
1242+
iterations--;
1243+
}
1244+
} else {
1245+
while (currentVal >= gen.timestepRange.end && iterations > 0) {
1246+
gen.size++;
1247+
gen.index++;
1248+
const result = f(currentVal);
1249+
gen.values.push(Array.isArray(result) ? result.join(' ') : result);
1250+
currentVal += gen.timestepRange.step;
1251+
iterations--;
1252+
}
1253+
}
1254+
}
1255+
funktionPrint(( 1 !== 2 ? "yes" : "no"));
1256+
rl.close()
1257+
`)
1258+
},
10441259
];
10451260

10461261
describe("The code generator", () => {

test/parser.test.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ const syntaxChecks = [
1515
["function with 2x", "f(x)=2x"],
1616
["function call through step", "f(x).step(3)"],
1717
["variable with colon", "print(x:2)"],
18-
["function call with multiple steps", "{G(x) + f(x)}.step(2)"],
1918
["print statement", 'print("Hello, World!")'],
2019
["print statement with special characters", 'print("\\n\\t\\r\\b\\\\\\"")'],
2120
["mixing arithmetic operators", "print(7 * 2 / 1 ** -5 + 2 % 2)"],
@@ -46,7 +45,6 @@ const syntaxChecks = [
4645
["commenting", 'print("hi") //This is a comment'],
4746
["using input as a function with arithmetic operation", "f(x)=input() + 2"],
4847
["function with slices", "f(x) = x \\ x + 1 \\ x + 2"],
49-
["multi-line function with slices", "f(x) = x \\ \n x + 1 \\ \n x + 2"],
5048
["function with slices and step call", "f(x) = x \\ x + 1 \\ x + 2\nf(x).step(2)"],
5149
];
5250

0 commit comments

Comments
 (0)