From 79f27cd453c4f3abb2429cdb6644f407150f9a26 Mon Sep 17 00:00:00 2001 From: Chris Johnson Date: Thu, 4 Jul 2024 18:23:13 -0400 Subject: [PATCH] Refactor builtin functions for extension. --- src/ast.js | 19 ++++---- src/blocks2tree.js | 18 +++++--- src/common.js | 4 +- src/text2tree.js | 106 ++++++++++++++++++--------------------------- src/tree2blocks.js | 27 +++++------- src/tree2text.js | 21 ++++----- 6 files changed, 89 insertions(+), 106 deletions(-) diff --git a/src/ast.js b/src/ast.js index 3a34c79..22fa3e0 100644 --- a/src/ast.js +++ b/src/ast.js @@ -121,14 +121,17 @@ export function createExecutable(tree) { case NODETYPES.INPUT: return new Praxly_input(tree); - case NODETYPES.RANDOM: - return new Praxly_random(tree); - - case NODETYPES.RANDOM_INT: - return new Praxly_random_int(createExecutable(tree.max), tree); - - case NODETYPES.RANDOM_SEED: - return new Praxly_random_seed(createExecutable(tree.seed), tree); + case NODETYPES.BUILTIN_FUNCTION_CALL: { + if (tree.name === 'random') { + return new Praxly_random(tree); + } else if (tree.name === 'randomInt') { + return new Praxly_random_int(createExecutable(tree.parameters[0]), tree); + } else if (tree.name === 'randomSeed') { + return new Praxly_random_seed(createExecutable(tree.parameters[0]), tree); + } else { + throw new Error('unknown builtin function'); + } + } case NODETYPES.SPECIAL_STRING_FUNCCALL: var args = []; diff --git a/src/blocks2tree.js b/src/blocks2tree.js index 42e70b2..24fddf7 100644 --- a/src/blocks2tree.js +++ b/src/blocks2tree.js @@ -81,26 +81,34 @@ export const makeGenerator = () => { praxlyGenerator['praxly_random_block'] = (block) => { return { + name: 'random', blockID: block.id, - type: NODETYPES.RANDOM, + type: NODETYPES.BUILTIN_FUNCTION_CALL, + parameters: [], }; } praxlyGenerator['praxly_random_int_block'] = (block) => { const expression = block.getInputTargetBlock('MAX'); return { + name: 'randomInt', blockID: block.id, - type: NODETYPES.RANDOM_INT, - max: praxlyGenerator[expression.type](expression), + type: NODETYPES.BUILTIN_FUNCTION_CALL, + parameters: [ + praxlyGenerator[expression.type](expression), + ], }; } praxlyGenerator['praxly_random_seed_block'] = (block) => { const expression = block.getInputTargetBlock('SEED'); return { + name: 'randomSeed', blockID: block.id, - type: NODETYPES.RANDOM_SEED, - seed: praxlyGenerator[expression.type](expression), + type: NODETYPES.BUILTIN_FUNCTION_CALL, + parameters: [ + praxlyGenerator[expression.type](expression), + ], }; } diff --git a/src/common.js b/src/common.js index fb5d1d0..662e067 100644 --- a/src/common.js +++ b/src/common.js @@ -62,9 +62,7 @@ export const NODETYPES = { ...TYPES, PRINT: "PRINT", PRINTLN: "PRINTLN", - RANDOM: "RANDOM", - RANDOM_INT: "RANDOM_INT", - RANDOM_SEED: "RANDOM_SEED", + BUILTIN_FUNCTION_CALL: "BUILTIN_FUNCTION_CALL", INPUT: "INPUT", CODEBLOCK: "CODEBLOCK", PROGRAM: "PROGRAM", diff --git a/src/text2tree.js b/src/text2tree.js index b9b404c..3879a75 100644 --- a/src/text2tree.js +++ b/src/text2tree.js @@ -600,48 +600,10 @@ class Parser { this.tokens[this.i].token_type = NODETYPES.INPUT; this.advance(); return this.literalNode_new(this.tokens[this.i - 1]); - case 'random': { - const randomToken = this.advance(); - if (this.has('(')) { - this.advance(); - if (this.has(')')) { - const rightParenthesisToken = this.advance(); - return { - blockID: "code", - line, - type: NODETYPES.RANDOM, - startIndex: randomToken.startIndex, - endIndex: rightParenthesisToken.endIndex, - }; - } else { - textError('parsing', 'did not detect right parenthesis', line); - } - } else { - textError('parsing', 'did not detect left parenthesis', line); - } - } - case 'randomInt': { - const randomToken = this.advance(); - if (this.has('(')) { - this.advance(); - const max = this.parse_expression(9); - if (this.has(')')) { - const rightParenthesisToken = this.advance(); - return { - blockID: "code", - line, - max, - type: NODETYPES.RANDOM_INT, - startIndex: randomToken.startIndex, - endIndex: rightParenthesisToken.endIndex, - }; - } else { - textError('parsing', 'did not detect right parenthesis', line); - } - } else { - textError('parsing', 'did not detect left parenthesis', line); - } - } + case 'random': + case 'randomInt': + return this.parse_builtin_function_call(line); + case NODETYPES.BOOLEAN: this.advance(); return this.literalNode_new(this.tokens[this.i - 1]); @@ -735,8 +697,42 @@ class Parser { } } + parse_builtin_function_call(line) { + // Assumes identifier token is up. + const nameToken = this.advance(); + if (this.has('(')) { + this.advance(); + // Expect 0 or more parameters. + const parameters = []; + if (this.hasNot(')')) { + const parameter = this.parse_expression(9); + parameters.push(parameter); + while (this.has(',')) { + this.advance(); + const parameter = this.parse_expression(9); + parameters.push(parameter); + } + } + if (this.has(')')) { + const rightParenthesisToken = this.advance(); + return { + blockID: "code", + name: nameToken.value, + line, + parameters, + type: NODETYPES.BUILTIN_FUNCTION_CALL, + startIndex: nameToken.startIndex, + endIndex: rightParenthesisToken.endIndex, + }; + } else { + textError('parsing', 'did not detect right parenthesis', line); + } + } else { + textError('parsing', 'did not detect left parenthesis', line); + } + } parse_location() { var result = { @@ -1056,31 +1052,11 @@ class Parser { } else if (this.has("randomSeed")) { - const randomToken = this.advance(); - if (this.has('(')) { + const node = this.parse_builtin_function_call(line); + if (this.has(';')) { this.advance(); - const seed = this.parse_expression(9); - if (this.has(')')) { - const rightParenthesisToken = this.advance(); - - if (this.has(';')) { - this.advance(); - } - - return { - blockID: "code", - line, - seed, - type: NODETYPES.RANDOM_SEED, - startIndex: randomToken.startIndex, - endIndex: rightParenthesisToken.endIndex, - }; - } else { - textError('parsing', 'did not detect right parenthesis', line); - } - } else { - textError('parsing', 'did not detect left parenthesis', line); } + return node; } else if (this.has("return")) { diff --git a/src/tree2blocks.js b/src/tree2blocks.js index ea40b3d..bfb5831 100644 --- a/src/tree2blocks.js +++ b/src/tree2blocks.js @@ -130,21 +130,18 @@ export const tree2blocks = (workspace, node) => { result = workspace.newBlock('praxly_input_block'); break; - case NODETYPES.RANDOM: - result = workspace.newBlock('praxly_random_block'); - break; - - case NODETYPES.RANDOM_INT: { - result = workspace.newBlock('praxly_random_int_block'); - const child = tree2blocks(workspace, node?.max); - result.getInput('MAX').connection.connect(child?.outputConnection); - break; - } - - case NODETYPES.RANDOM_SEED: { - result = workspace.newBlock('praxly_random_seed_block'); - const child = tree2blocks(workspace, node?.seed); - result.getInput('SEED').connection.connect(child?.outputConnection); + case NODETYPES.BUILTIN_FUNCTION_CALL: { + if (node.name === 'random') { + result = workspace.newBlock('praxly_random_block'); + } else if (node.name === 'randomInt') { + result = workspace.newBlock('praxly_random_int_block'); + const child = tree2blocks(workspace, node?.parameters[0]); + result.getInput('MAX').connection.connect(child?.outputConnection); + } else if (node.name === 'randomSeed') { + result = workspace.newBlock('praxly_random_seed_block'); + const child = tree2blocks(workspace, node?.parameters[0]); + result.getInput('SEED').connection.connect(child?.outputConnection); + } break; } diff --git a/src/tree2text.js b/src/tree2text.js index 9b5fd53..c3c53ce 100644 --- a/src/tree2text.js +++ b/src/tree2text.js @@ -164,16 +164,17 @@ export const tree2text = (node, indentation) => { case NODETYPES.INPUT: return "input"; - case NODETYPES.RANDOM: - return "random()"; - - case NODETYPES.RANDOM_INT: - const max = tree2text(node.max, indentation); - return `randomInt(${max})`; - - case NODETYPES.RANDOM_SEED: - const seed = tree2text(node.seed, indentation); - return `randomSeed(${seed})\n`; + case NODETYPES.BUILTIN_FUNCTION_CALL: { + if (node.name === 'random') { + return "random()"; + } else if (node.name === 'randomInt') { + const max = tree2text(node.parameters[0], indentation); + return `randomInt(${max})`; + } else if (node.name === 'randomSeed') { + const seed = tree2text(node.parameters[0], indentation); + return `randomSeed(${seed})\n`; + } + } case NODETYPES.RETURN: var result = ' '.repeat(indentation) + "return ";