From 2de4cac1affd94f3bf7a6cb230c044e30b7f18cd Mon Sep 17 00:00:00 2001 From: Shautvast Date: Sat, 7 Dec 2024 22:51:55 +0100 Subject: [PATCH] bugfixes and looping --- js/app.js | 2 +- js/interpreter.js | 73 ++++++++++++++++++++------- js/parser.js | 101 +++++++++++++++++++++++++++----------- js/scanner.js | 4 +- package.json | 2 +- szpaks/wobble_block.szpak | 65 ++++++++++++++++++++++++ 6 files changed, 199 insertions(+), 48 deletions(-) create mode 100644 szpaks/wobble_block.szpak diff --git a/js/app.js b/js/app.js index e14f0be..d098d27 100644 --- a/js/app.js +++ b/js/app.js @@ -75,7 +75,7 @@ import {interpret} from "./interpreter.js"; try { canvas.clearRect(0, 0, width, height); - interpret({canvas: canvas, x: tx, y: ty, angle: tangle, unit: 10, width, height}, script); + interpret({canvas: canvas, x: tx, y: ty, angle: tangle, unit: 10, width:width, height:height}, script); } catch (Exception) { } } diff --git a/js/interpreter.js b/js/interpreter.js index fd7507e..57dffb4 100644 --- a/js/interpreter.js +++ b/js/interpreter.js @@ -37,6 +37,30 @@ export function interpret(init_env, code) { THIS.executeBlock(statements, {enclosing: THIS.current_environment}); }, + visitParametrizedBlock: (argList, statements) => { + let args = argList.map(THIS.evaluate); + let start,end; + if (args.length===2){ + start = args[0]; + end = args[1]; + } else { + start =0; + end = args[0]; + } + let previous = THIS.current_environment; + THIS.current_environment = {enclosing: previous}; + try { + for (let i = start; i < end; i++) { + THIS.current_environment.it = i; + for (let i = 0; i < statements.length; i++) { + THIS.execute(statements[i]); + } + } + } finally { + THIS.current_environment = previous; + } + }, + visitExpressionStatement: (expression) => { THIS.evaluate(expression); }, @@ -50,27 +74,43 @@ export function interpret(init_env, code) { }, visitPrintStatement: (expression) => { - console.log(THIS.current_environment); let value = THIS.evaluate(expression); console.log(THIS.stringify(value)); }, visitCallStatement: (fun, argList) => { let args = argList.map(THIS.evaluate); - switch (fun){ - case "start": THIS.start(...args); break; - case "go": THIS.go(...args); break; - case "turn": THIS.turn(...args); break; - case "left": THIS.left(...args); break; - case "right": THIS.right(...args); break; - case "pillars": THIS.pillars(...args); break; - case "moving_pillars": THIS.moving_pillars(...args); break; - case "staircase": THIS.staircase(...args); break; - default: throw "Unknown function: " + fun; + switch (fun) { + case "start": + THIS.start(...args); + break; + case "go": + THIS.go(...args); + break; + case "turn": + THIS.turn(...args); + break; + case "left": + THIS.left(...args); + break; + case "right": + THIS.right(...args); + break; + case "pillars": + THIS.pillars(...args); + break; + case "moving_pillars": + THIS.moving_pillars(...args); + break; + case "staircase": + THIS.staircase(...args); + break; + default: + throw "Unknown function: " + fun; } }, - start: (x,y) => { + start: (x, y) => { tx = x * unit; ty = y * unit; tangle = 0; @@ -129,7 +169,7 @@ export function interpret(init_env, code) { } }, - staircase: (number_of_steps, size, direction = DOWN) =>{ + staircase: (number_of_steps, size, direction = DOWN) => { const angle = direction === DOWN ? 90 : -90; for (let i = 0; i < number_of_steps; i++) { THIS.go(size); @@ -151,9 +191,9 @@ export function interpret(init_env, code) { } }, - visitBinaryExpr: (operator, _left, _right) => { - let left = THIS.evaluate(_left); - let right = THIS.evaluate(_right); + visitBinaryExpr: (operator, l, r) => { + let left = THIS.evaluate(l); + let right = THIS.evaluate(r); switch (operator.type) { case MINUS: @@ -230,7 +270,6 @@ export function interpret(init_env, code) { try { const statements = parse(code); for (let i = 0; i < statements.length; i++) { - THIS.execute(statements[i]); } } catch (e) { diff --git a/js/parser.js b/js/parser.js index 9562518..8e4fa28 100644 --- a/js/parser.js +++ b/js/parser.js @@ -1,14 +1,42 @@ import "./scanner"; import { - scan, error, - BANG, BANG_EQUAL, EOF, - EQUAL, EQUAL_EQUAL, - FALSE, GREATER, - GREATER_EQUAL, IDENTIFIER, - LEFT_BRACE, LEFT_PAREN, LESS, - LESS_EQUAL, MINUS, NUMBER, PLUS, - PRINT, RIGHT_BRACE, RIGHT_PAREN, - SEMICOLON, SLASH, STAR, STRING, TRUE, VAR, START, COMMA, GO, STAIRCASE, PILLARS, MOVING_PILLARS, LEFT, RIGHT, TURN + scan, + error, + BANG, + BANG_EQUAL, + EOF, + EQUAL, + EQUAL_EQUAL, + FALSE, + GREATER, + GREATER_EQUAL, + IDENTIFIER, + LEFT_BRACE, + LEFT_PAREN, + LESS, + LESS_EQUAL, + MINUS, + NUMBER, + PLUS, + PRINT, + RIGHT_BRACE, + RIGHT_PAREN, + SEMICOLON, + SLASH, + STAR, + STRING, + TRUE, + VAR, + START, + COMMA, + GO, + STAIRCASE, + PILLARS, + MOVING_PILLARS, + LEFT, + RIGHT, + TURN, + REPEAT } from "./scanner"; export function parse(code) { @@ -38,7 +66,7 @@ export function parse(code) { initializer = expression(); } consume(SEMICOLON, "Expected semicolon"); - return {accept: (visitor) => visitor.visitVariableStatement(name, initializer)}; + return {class: "var", name:name, initializer: initializer, accept: (visitor) => visitor.visitVariableStatement(name, initializer)}; } const statement = () => { @@ -69,8 +97,12 @@ export function parse(code) { if (match(MOVING_PILLARS)) { return callStatement("moving_pillars"); } + if (match(REPEAT)){ + return call_block(); + } if (match(LEFT_BRACE)) { - return {accept: (visitor) => visitor.visitBlockStatement(block())}; + const blockStatement = block(); + return {class: "block", accept: (visitor) => visitor.visitBlockStatement(blockStatement)}; } return expressionStatement(); @@ -80,7 +112,7 @@ export function parse(code) { return assignment(); } - const expressions = () => { + const arg_expressions = () => { consume(LEFT_PAREN, "Expect '('"); let exprs = [expression()]; while (match(COMMA)) { @@ -98,7 +130,7 @@ export function parse(code) { if (expr.class === 'Variable') { let name = expr.name; - return {accept: (visitor) => visitor.visitAssignExpr(name, value)}; + return {class: "assign", var_name: name, init_expr: value, accept: (visitor) => visitor.visitAssignExpr(name, value)}; } throw error(equals, "Invalid assignment target."); @@ -109,19 +141,26 @@ export function parse(code) { const printStatement = () => { const value = expression(); consume(SEMICOLON, "Expected semicolon"); - return {accept: (visitor) => visitor.visitPrintStatement(value)}; + return {class: "print", value: value, accept: (visitor) => visitor.visitPrintStatement(value)}; } const callStatement = (name) => { - const values = expressions(); + const args = arg_expressions(); consume(SEMICOLON, "Expected semicolon"); - return {accept: (visitor) => visitor.visitCallStatement(name, values)}; + return {class: "call", accept: (visitor) => visitor.visitCallStatement(name, args)}; + } + + const call_block = () =>{ + const args = arg_expressions(); + consume(LEFT_BRACE, "Expect block"); + const action = block(); + return {class: "block", accept: (visitor)=> visitor.visitParametrizedBlock(args, action)}; } const expressionStatement = () => { const value = expression(); consume(SEMICOLON, "Expected semicolon"); - return {accept: (visitor) => visitor.visitExpressionStatement(value)}; + return {class: "expressionStatement", expression: value, accept: (visitor) => visitor.visitExpressionStatement(value)}; } const block = () => { @@ -138,7 +177,8 @@ export function parse(code) { while (match(BANG_EQUAL, EQUAL_EQUAL)) { let operator = previous(); let right = comparison(); - expr = {accept: (visitor) => visitor.visitBinaryExpr(operator, expr, right)}; + const left = expr; + expr = {class: "binaryExpr", operator: operator, left: expr, right: right, accept: (visitor) => visitor.visitBinaryExpr(operator, left, right)}; } return expr; } @@ -148,7 +188,8 @@ export function parse(code) { while (match(GREATER, GREATER_EQUAL, LESS, LESS_EQUAL)) { let operator = previous(); let right = term(); - expr = {accept: (visitor) => visitor.visitBinaryExpr(operator, expr, right)}; + const left = expr; + expr = {class: "binaryExpr", operator: operator, left: expr, right: right, accept: (visitor) => visitor.visitBinaryExpr(operator, left, right)}; } return expr; } @@ -158,7 +199,8 @@ export function parse(code) { while (match(MINUS, PLUS)) { let operator = previous(); let right = factor(); - expr = {accept: (visitor) => visitor.visitBinaryExpr(operator, expr, right)}; + const left = expr; + expr = {class: "binaryExpr", operator: operator, left: expr, right: right, accept: (visitor) => visitor.visitBinaryExpr(operator, left, right)}; } return expr; } @@ -168,7 +210,8 @@ export function parse(code) { while (match(SLASH, STAR)) { let operator = previous(); let right = unary(); - expr = {accept: (visitor) => visitor.visitBinaryExpr(operator, expr, right)}; + const left = expr; + expr = {class: "binaryExpr", operator: operator, left: expr, right: right, accept: (visitor) => visitor.visitBinaryExpr(operator, left, right)}; } return expr; } @@ -177,36 +220,36 @@ export function parse(code) { if (match(BANG, MINUS)) { let operator = previous(); let right = unary(); - return {accept: (visitor) => visitor.visitUnaryExpr(operator, right)}; + return {class: "unaryExpr", operator: operator, right: right, accept: (visitor) => visitor.visitUnaryExpr(operator, right)}; } return primary(); } const primary = () => { if (match(FALSE)) { - return {accept: (visitor) => visitor.visitLiteralExpr(false)}; + return {class: "boolean", value: false, accept: (visitor) => visitor.visitLiteralExpr(false)}; } if (match(TRUE)) { - return {accept: (visitor) => visitor.visitLiteralExpr(true)}; + return {class: "boolean", value: true, accept: (visitor) => visitor.visitLiteralExpr(true)}; } if (check(NUMBER)) { advance(); let number = parseFloat(previous().literal); - return {accept: (visitor) => visitor.visitLiteralExpr(number)}; + return {class: "number", value:number, accept: (visitor) => visitor.visitLiteralExpr(number)}; } if (check(STRING)) { advance(); let string = previous().literal; - return {accept: (visitor) => visitor.visitLiteralExpr(string)}; + return {class: "string", value: string, accept: (visitor) => visitor.visitLiteralExpr(string)}; } if (match(IDENTIFIER)) { let identifier = previous(); - return {class: "Variable", accept: (visitor) => visitor.visitVariableExpr(identifier)}; + return {class: "Variable", identifier: identifier, accept: (visitor) => visitor.visitVariableExpr(identifier)}; } if (match(LEFT_PAREN)) { let expr = expression(); consume(RIGHT_PAREN, "Expect ')' after expression."); - return {accept: (visitor) => visitor.visitGroupingExpr(expr)}; + return {class: "groupExpr", expression: expr, accept: (visitor) => visitor.visitGroupingExpr(expr)}; } throw error(peek(), "Expect expression."); } @@ -225,10 +268,12 @@ export function parse(code) { return true; } } + return false; } const check = (type) => { + // console.log(peek().type+"==="+type); if (is_at_end()) { return false; } diff --git a/js/scanner.js b/js/scanner.js index 64c065b..4247590 100644 --- a/js/scanner.js +++ b/js/scanner.js @@ -241,6 +241,7 @@ export const RIGHT = 41; export const PILLARS = 42; export const MOVING_PILLARS = 43; export const STAIRCASE = 44; +export const REPEAT = 45; export const keywords = new Map([ ["and", AND], @@ -262,5 +263,6 @@ export const keywords = new Map([ ["right", RIGHT], ["pillars", PILLARS], ["moving_pillars", MOVING_PILLARS], - ["staircase", STAIRCASE] + ["staircase", STAIRCASE], + ["repeat", REPEAT], ]) diff --git a/package.json b/package.json index b7438a8..c43ea4e 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": " ", + "name": "szpakowski-lang", "version": "0.0.1", "description": "", "private": true, diff --git a/szpaks/wobble_block.szpak b/szpaks/wobble_block.szpak new file mode 100644 index 0000000..7060dac --- /dev/null +++ b/szpaks/wobble_block.szpak @@ -0,0 +1,65 @@ +start(0, 20); +go(1); +staircase(2, 1, DOWN); +go(2); +left(90); +go(1); +left(90); +staircase(2, 1, DOWN); +go(1); +right(90); +go(6); +right(90); +go(1); +right(90); +go(5); +left(90); +staircase(2, 1, DOWN); +go(1); +right(90); +go(2); +left(90); +go(1); +left(90); +go(3); +left(90); +staircase(2, 1, DOWN); +go(1); +right(90); +go(4); +right(90); +go(1); +right(90); +go(3); +left(90); +staircase(2, 1, DOWN); +go(1); +right(90); +go(4); +left(90); +go(1); +left(90); +go(5); +left(90); +staircase(2, 1, DOWN); +go(1); +right(90); +go(2); +right(90); +go(1); +right(90); +go(1); +left(90); +staircase(2, 1, DOWN); +go(1); +right(90); +go(6); +left(90); +go(1); +left(90); +go(7); +left(90); +staircase(2, 1, DOWN); +go(1); +right(90); +go(3);