Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automated block gemeration #13

Draft
wants to merge 23 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
8c36d80
added and loading txt file
N-J-Martin Mar 16, 2024
6170bd7
starting to use regex to build the message for the block
N-J-Martin Mar 17, 2024
83dc45c
creates most basic blocks automatically reading regex from essenceBNF
N-J-Martin Mar 18, 2024
30221a4
generates declarations code
N-J-Martin Mar 19, 2024
f5fba9a
removed dodgy download, should work fine now
N-J-Martin Mar 21, 2024
3687f2b
doesn't like blocky typed vars
N-J-Martin Mar 22, 2024
dec5a8c
reading lists but found bug with reading reading values.
N-J-Martin Mar 23, 2024
f19e45e
fix essence generation and has correct brackets, unsure how to ensure…
N-J-Martin Mar 23, 2024
f7ca0d7
fixed brackets
N-J-Martin Mar 23, 2024
49eb66b
allow | in statements
N-J-Martin Mar 23, 2024
3c49267
removed comments from blocks that produce text with |
N-J-Martin Mar 23, 2024
3be9964
added scrollbars to workspace
N-J-Martin Mar 23, 2024
ba0efd6
added value blocks, using ===== to separate
N-J-Martin Mar 25, 2024
b6489b1
fix quoted regex
N-J-Martin Mar 25, 2024
8e48c35
separated code into functions.
N-J-Martin Mar 25, 2024
9cd9429
added category toolbox
N-J-Martin Mar 26, 2024
c77bef3
added typing
N-J-Martin Mar 28, 2024
7786903
got variables working on main WS
N-J-Martin Mar 28, 2024
7c8c4e1
have variables consistent across data and main WS
N-J-Martin Mar 28, 2024
e8b3b3e
variables only linked one way.
N-J-Martin Mar 28, 2024
cc7463a
fixed args typo.
N-J-Martin Mar 30, 2024
9e38319
cleaned up unneeded code, remove old essence blocks and generator
N-J-Martin Mar 31, 2024
7160009
added operations (execept abs)
N-J-Martin May 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
"webpack-dev-server": "^5.0.2"
},
"dependencies": {
"@blockly/plugin-typed-variable-modal": "^7.0.10",
"blockly": "^10.4.2"
}
}
357 changes: 357 additions & 0 deletions src/blocks/autoEssence.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,357 @@
import file from './essenceBNF.txt';
import * as Blockly from 'blockly';
export const essenceGenerator = new Blockly.Generator('essence');


let stages = ["statements", "values", "categories"];
let stage = stages[0];

let blockArray = [];
let usedBlocks = [];
let categories = {};

let usableLines = getUsableLines();

for (let b of usableLines){
if (b == "=====") {
stage = stages[stages.indexOf(stage) + 1];
continue;
}



let def = /\w+(?= :=)/;
let name = def.exec(b);
let definitions = getDefinitions(b);

if (stage == "statements" || stage == "values") {
let index = 1;
for (let definition of definitions){
// get list part and remove
definition = dealWithLists(definition);
let metadata = getMessageAndArgs(definition);
let message = metadata[0];
let args = metadata[1];

// diff block types
if (stage == "statements") {
blockArray.push(createBlockJSON(name[0].trim()+index, message.trim(), args));
addTranslation(name[0].trim()+index, args, message.trim());
} else if (stage == "values") {
blockArray.push(createValueJSON(name[0].trim()+index, message.trim(), args));
addValueTranslation(name[0].trim()+index, args, message.trim());
}

index++;
}
} else {
let contents = [];
for (let d of definitions) {
d = d.trim();
if (categories[d] == null){
for (let b of blockArray) {
if (b.type.startsWith(d)) {
contents.push({
"kind" : "block",
"type": b.type
});
usedBlocks.push(b);
}
}
} else {
contents.push({
"kind": "category",
"name": d,
"contents": categories[d]
})
categories[d] = null;

}
}
let type = name[0].trim();
categories[type] = contents;
}
}

let toolboxJSON = getToolBoxJSON();
export const toolbox = toolboxJSON;
addTypeChecks();
blockArray.push({"type": "variables_get",
"message0": "%1",
"args0": [
{ // Beginning of the field variable dropdown
"type": "field_variable",
"name": "VAR", // Static name of the field
"variable": "%{BKY_VARIABLES_DEFAULT_NAME}" // Given at runtime
} // End of the field variable dropdown
],
"output": "Name"
});

export const blocks = Blockly.common.createBlockDefinitionsFromJsonArray(blockArray);

function createBlockJSON(name, message, args){
let jsonArgs = [];
for (let a of args){
let json = {
"type": "input_value",
"name": a
}
if (a.trim() == "Array"){
json.check = "Array";
}
if (a.trim() == "Name"){
json.check = "Name";
}

jsonArgs.push(json);
}
// change args names to check types later?
return {
"type": name,
"message0": message,
"args0": jsonArgs,
"inputsInline": true,
"previousStatement": null,
"nextStatement": null,
"colour": 210,
"tooltip": "",
"helpUrl": ""
};
}

function createValueJSON(name, message, args){
let jsonArgs = [];
for (let a of args){
let json = {
"type": "input_value",
"name": a,
}
if (a.trim() == "Array"){
json.check = "Array";
}
if (a.trim() == "Name"){
json.check = "Name";
}

jsonArgs.push(json);
};

return {
"type": name,
"message0": message,
"args0": jsonArgs,
"output": name,
"inputsInline": true,
"colour": 290,
"tooltip": "",
"helpUrl": ""
}
}

function addTranslation(name, args, message){
essenceGenerator.forBlock[name] = function (block, generator) {
let code = message;
for (let i = 1; i <= args.length; i++) {
// no precedence currently
code = code.replace(`%${i}`, `${generator.valueToCode(block, args[i-1], 0)}`);
}
return code;
};
}

function addValueTranslation(name, args, message){
essenceGenerator.forBlock[name] = function (block, generator) {
let code = message;
for (let i = 1; i <= args.length; i++) {
// no precedence currently
code = code.replace(`%${i}`, `${generator.valueToCode(block, args[i-1], 0)}`);
}
return [code, 0];
};
}

function getToolBoxJSON() {
let othercontent = [];
for (let b of blockArray){
if (!(usedBlocks.includes(b))){
othercontent.push({
"kind": "block",
"type": b.type
});
}
}

let toolbox = {
"kind": "categoryToolbox",
"contents": [
{
"kind": "category",
"name": "core",
"contents": [
{
'kind': 'block',
'type': 'math_number'
},
{
'kind': 'block',
'type': 'lists_create_with'
},
{
'kind': 'block',
'type': 'text'
}
]
},
// use built in variable category
{
"kind": "category",
"name": "Variables",
"custom": "VARIABLES"
},
{
"kind": "category",
"name": "other",
"contents": othercontent
}
]

};

for (let c in categories){
toolbox.contents.push({
"kind": "category",
"name": c,
"contents": categories[c]
});
}
return toolbox;
}

function addTypeChecks() {
for (let b of blockArray){
let inputTypes = [];
for (let a of b.args0){
let type = a.name.trim();
// adds all
if (categories[type] != null){
for (let t in categories[type]){
inputTypes.push(t.type);
}
} else {
for (let bl of blockArray){
if (type != "Name" && type != "Array" && bl.type.startsWith(type)){
inputTypes.push(bl.type);
}
}
}
if (inputTypes.length > 0){
a['check'] = inputTypes;
}

}
}
}

function getUsableLines() {
let lines = file.split("\r\n");
let comment = /^!/;
let usable = [];
for (let s of lines){
if (! (comment.test(s)) & (s.trim() != '')) {
usable.push(s);
}
}

return usable;
}

function getDefinitions(line) {
let allDefinitions = line.slice(line.indexOf("=") + 1);
let definitions = allDefinitions.split("|");
return definitions;
}

function dealWithLists(definition) {
let list = /list\([\w\d\s,"{}\[\]\(\)]+\)/g;
let lists = definition.matchAll(list);
let newList;
for (let l of lists){
if (l[0].includes("{}")){
newList = "{Array}";
} else if (l[0].includes("[]")){
newList = "[Array]";
} else if (l[0].includes("()")){
newList = "(Array)";
} else {
newList = "Array";
}
};


definition = definition.replaceAll(list, newList);
return definition;
}

function getMessageAndArgs(definition){
let quoted = /\"[\w\:\s\(\)\.]*\"/g;
let matches = definition.matchAll(quoted);
// replace quoted parts with #, so can replace words not # into arg stand ins - %1 etc (and get the type for them)
let replaced = definition.replaceAll(quoted, "#");
let argsTypes = replaced.matchAll(/\w+/g);
let argsReplaced = replaced;
let count = 1;
let args = []
for (let a of argsTypes){
argsReplaced = argsReplaced.replace(/([A-Z]|[a-z])+/, `%${count}`);
let newArg = a[0].trim();
while (args.includes(newArg)){
newArg = newArg + " ";
}
args.push(newArg);
count++;
}

// replace the text back into the message
let message = argsReplaced;
for (let m of matches) {
message = message.replace(/#/, m);
}
message = message.replaceAll(/"/g, "");
return [message, args];
}

essenceGenerator.scrub_ = function(block, code, thisOnly) {
const nextBlock =
block.nextConnection && block.nextConnection.targetBlock();
if (nextBlock && !thisOnly) {
return code + '\n' + essenceGenerator.blockToCode(nextBlock);
}
return code;
};

essenceGenerator.forBlock['lists_create_with'] = function(block, generator) {
const values = [];
for (let i = 0; i < block.itemCount_; i++) {
const valueCode = generator.valueToCode(block, 'ADD' + i,
Order.ATOMIC);
if (valueCode) {
values.push(valueCode);
}
}
const valueString = values.join(', ');
const codeString = `${valueString}`;
return [codeString, 0];
};

essenceGenerator.forBlock['math_number'] = function(block) {
const code = String(block.getFieldValue('NUM'));
return [code, 0];
};


essenceGenerator.forBlock['text'] = function(block) {
const textValue = block.getFieldValue('TEXT');
const code = `${textValue}`;
return [code, 0];
};
Loading