lots of things

This commit is contained in:
Shautvast 2024-12-09 22:22:57 +01:00
parent 4f574e4198
commit 21daf0d4be
7 changed files with 246 additions and 137 deletions

View file

@ -1,48 +1,64 @@
html {
color: #222;
background: rgb(249,235,213);
font-size: 1em;
line-height: 1.4;
overflow: hidden;
}
#console {
font: 13px monospace, sans-serif;
padding: 5px;
color: greenyellow;
background: black;
color: black;
background: rgb(255,241,219);
position: fixed;
right: 10px;
bottom: 0;
width: 30%;
height: 20em;
right: 1px;
bottom: 4em;
width: 30em;
height: 90%;
border: 2px solid darkgray;
border-radius: 10px;
z-index: 0;
}
#help{
background: black;
font: 13px monospace, sans-serif;
padding: 5px;
width: 90%;
color: greenyellow;
position: absolute;
background: rgb(249,235,213);
font: 13px monospace, sans-serif;
padding-left: 5px;
width: 90%;
color: black;
z-index: 2;
scroll-behavior: auto;
overflow: auto;
border: none transparent;
}
#command_input {
background: black;
color: greenyellow;
background: rgb(255,241,219);
color: black;
outline: none;
width: 90%;
height: 20em;
height: 99%;
resize: none;
}
#log{
font: 13px monospace, sans-serif;
padding: 5px;
color: black;
background: rgb(255,241,219);
position: fixed;
right: 1px;
bottom: 0;
width: 40em;
height: 2em;
border: 2px solid darkgray;
border-radius: 10px;
z-index: 0;
}
.multiline {
border: none transparent;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
}
.single_line {

View file

@ -29,10 +29,10 @@ moving_pillars(5, 10,1, false);
</label>
</div>
<textarea id="help" style="visibility: hidden"></textarea>
<span id="help" style="visibility: hidden"></span>
<div id="log"></div>
<script src="js/app.js"></script>
</body>
</html>

View file

@ -5,14 +5,21 @@ import {interpret} from "./interpreter.js";
const command_input_element = document.getElementById('command_input');
const canvas_element = document.getElementById('canvas');
const canvas = canvas_element.getContext('2d');
const width = canvas_element.width = window.innerWidth;
const height = canvas_element.height = window.innerHeight;
canvas.fillStyle = 'white';
canvas.strokeStyle = 'black';
const width = window.innerWidth;
const height = window.innerHeight;
canvas.clearRect(0, 0, width, height);
canvas.lineWidth = 2;
canvas.globalAlpha = 1;
canvas.strokeStyle = 'black';
canvas.fillStyle = 'black';
canvas_element.width = width;
canvas_element.height = height;
const help_element = document.getElementById('help');
let script;
let tx = 0;
let ty = 0;
let tangle = 0;
document.body.onkeydown = function (event) {
if (event.key === 'Tab') {
@ -20,6 +27,21 @@ import {interpret} from "./interpreter.js";
}
}
const count = function (string, substring) {
if (!substring) {
return 0;
}
let count = 0;
let pos = string.indexOf(substring);
while (pos !== -1) {
count++;
pos = string.indexOf(substring, pos + substring.length);
}
return count;
};
const help = [
{v1: "start(x,y)", v2: "start(0,0);"},
{v1: "go(distance)", v2: "go(1);"},
@ -27,9 +49,14 @@ import {interpret} from "./interpreter.js";
{v1: "left(angle)", v2: "left(90);"},
{v1: "right(angle)", v2: "right(90);"},
{v1: "pillars(number, length, shift = 0, direction = UP)", v2: "pillars(3, 10, 0, DOWN);"},
{v1: "moving_pillars(number, length, shift = 0, direction = DOWN)", v2: "moving_pillars(3, 10, 0, DOWN);"},
{v1: "moving_pillars(number, length, shift = 1, direction = DOWN)", v2: "moving_pillars(3, 10, 1, DOWN);"},
{v1: "staircase(number, size, direction = DOWN)", v2: "staircase(3, 1, DOWN);"},
{v1: "repeat([start], end){...}", v2: "repeat(5){\n}"},
{v1: "repeat([start], end){...}", v2: "repeat(5){\n \n}"},
{v1: "random(range-start, range-end)", v2: "random(0,1);"},
{v1: "sin(alpha)", v2: "sin();"},
{v1: "cos(alpha)", v2: "cos();"},
{v1: "tan(alpha)", v2: "tan();"},
{v1: "atan(tangent)", v2: "atan();"},
];
const slices = {};
for (let i = 0; i < help.length; i++) {
@ -43,11 +70,17 @@ import {interpret} from "./interpreter.js";
slices[help[i].v1] = [help[i]];
}
let tx = 0;
let ty = 0;
let tangle = 0;
function refresh() {
script = command_input_element.value;
try {
canvas.clearRect(0, 0, width, height);
interpret({canvas: canvas, x: tx, y: ty, angle: tangle, unit: 10, width: width, height: height}, script);
} catch (e) {
document.getElementById('log').innerHTML = e;
}
}
document.onkeyup = function (event) {
command_input_element.onkeyup = function handle_key_input(event) {
if (event.key === 'Tab') {
const script = command_input_element.value;
event.preventDefault();
@ -69,19 +102,6 @@ import {interpret} from "./interpreter.js";
refresh();
}
}
};
function refresh() {
script = command_input_element.value;
try {
canvas.clearRect(0, 0, width, height);
interpret({canvas: canvas, x: tx, y: ty, angle: tangle, unit: 10, width:width, height:height}, script);
} catch (Exception) {
}
}
command_input_element.onkeyup = function handle_key_input(event) {
if (!['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {
script = command_input_element.value;
@ -98,14 +118,17 @@ import {interpret} from "./interpreter.js";
const command = currentLineText.trim();
if (slices[command]) {
const help = slices[command].map(x => x.v1);
const help_text = help.join('\n');
let help_text = "";
for (let x = 0; x < help.length; x++) {
help_text += `<div id="l-${x}">${help[x]}</div>`;
}
const computedStyle = window.getComputedStyle(command_input_element);
const fontSize = parseFloat(computedStyle.fontSize);
const lineHeight = computedStyle.lineHeight === 'normal' ? fontSize * 1.2 : parseFloat(computedStyle.lineHeight);
const textBounding = command_input_element.getBoundingClientRect();
const topPosition = textBounding.top + window.scrollY;// + (cursor_position - startOfLine) * lineHeight/ script.split('\n').length;
const topPosition = textBounding.top + window.scrollY + (count(script, '\n') + 4) * lineHeight;
help_element.style.visibility = 'visible';
help_element.style.left = `${textBounding.left + window.scrollX}px`;
@ -116,7 +139,9 @@ import {interpret} from "./interpreter.js";
}
refresh();
}
};
}
//main
refresh();
})();
})
();

19
js/functions.js Normal file
View file

@ -0,0 +1,19 @@
export function random(s, e = 0) {
return Math.random() * (e - s) + s;
}
export function cos(a) {
return Math.cos(a);
}
export function sin(a) {
return Math.sin(a);
}
export function tan(a) {
return Math.tan(a);
}
export function atan(a) {
return Math.atan(a);
}

View file

@ -12,6 +12,7 @@ import {
SLASH,
STAR
} from "./scanner";
import {atan, cos, random, sin, tan} from "./functions";
export function interpret(init_env, code) {
@ -110,6 +111,22 @@ export function interpret(init_env, code) {
}
},
visitCallFunction: (name, argList) => {
let args = argList.map(THIS.evaluate);
switch (name) {
case "random":
return random(...args);
case "cos":
return cos(...args);
case "sin":
return sin(...args);
case "tan":
return tan(...args);
case "atan":
return atan(...args);
}
},
start: (x, y) => {
tx = x * unit;
ty = y * unit;
@ -159,11 +176,11 @@ export function interpret(init_env, code) {
length += shift;
for (let i = 0; i < n; i++) {
THIS.turn(-90);
THIS.go(direction === DOWN ? -length2 : length2);
THIS.go(direction === UP ? -length2 : length2);
THIS.turn(90);
THIS.go(1);
THIS.turn(90);
THIS.go(direction === DOWN ? -length : length);
THIS.go(direction === UP ? -length : length);
THIS.turn(-90);
THIS.go(1);
}
@ -269,6 +286,8 @@ export function interpret(init_env, code) {
const statements = parse(code);
for (let i = 0; i < statements.length; i++) {
// console.log(statements[i]);
THIS.execute(statements[i]);
}
}

View file

@ -36,10 +36,12 @@ import {
LEFT,
RIGHT,
TURN,
REPEAT
REPEAT, functions,
} from "./scanner";
export function parse(code) {
const log_console = document.getElementById("log");
const tokens = scan(code);
// console.log(tokens);
let current = 0;
@ -48,10 +50,12 @@ export function parse(code) {
let statements = [];
while (!is_at_end()) {
log_console.innerHTML = "OK";
try {
statements.push(declaration());
} catch (e) {
console.log(e);
// console.log(e);
log_console.innerHTML = e;
current = tokens.length - 1; // stop compiling
}
}
@ -163,7 +167,7 @@ export function parse(code) {
const callStatement = (name) => {
const args = arg_expressions();
consume(SEMICOLON, "Expected semicolon");
return {class: "call", accept: (visitor) => visitor.visitCallStatement(name, args)};
return {class: "call_stmt", accept: (visitor) => visitor.visitCallStatement(name, args)};
}
const call_block = () => {
@ -271,6 +275,16 @@ export function parse(code) {
accept: (visitor) => visitor.visitUnaryExpr(operator, right)
};
}
return fun();
}
const fun = () => {
let function_name = peek().lexeme;
if (functions.has(function_name)) {
advance();
let args = arg_expressions();
return {class: "call_fun", accept: (visitor) => visitor.visitCallFunction(function_name, args)};
}
return primary();
}
@ -307,7 +321,7 @@ export function parse(code) {
if (check(type)) {
return advance();
}
throw error(peek(), message);
throw error(peek(), message + " but was " + peek().lexeme);
}
const match = (...types) => {
@ -322,7 +336,6 @@ export function parse(code) {
}
const check = (type) => {
// console.log(peek().type+"==="+type);
if (is_at_end()) {
return false;
}

View file

@ -10,7 +10,7 @@ export const scan = (source) => {
scan_token();
}
tokens.push({type: EOF, lexeme: "", line: line});
tokens.push({type: EOF, lexeme: "EOF", line: line});
return tokens;
};
@ -107,8 +107,10 @@ export const scan = (source) => {
}
let text = source.substring(start, current);
let type = keywords.get(text);
if (type == null) {
if (type === undefined) {
type = functions.get(text);
}
if (type === undefined) {
type = IDENTIFIER;
}
add_token(type);
@ -153,7 +155,7 @@ export const scan = (source) => {
advance();
let value = source.substring(start + 1, current - 1);
console.log("string "+value);
// console.log("string " + value);
add_token(STRING, value);
}
@ -242,6 +244,11 @@ export const PILLARS = 42;
export const MOVING_PILLARS = 43;
export const STAIRCASE = 44;
export const REPEAT = 45;
export const RANDOM = 46;
export const COS = 47;
export const SIN = 48;
export const TAN = 49;
export const ATAN = 50;
export const keywords = new Map([
["and", AND],
@ -265,4 +272,14 @@ export const keywords = new Map([
["moving_pillars", MOVING_PILLARS],
["staircase", STAIRCASE],
["repeat", REPEAT],
])
["random", RANDOM],
]);
export const functions = new Map([
["random", RANDOM],
["cos", COS],
["sin", SIN],
["tan", TAN],
["atan", ATAN],
]);