实现原理
解析blockly语法树,使用js管理状态,实际使用lua执行,c/c++函数调用使用lua调用c/c++函数的能力
可以单行执行
已实现if功能
TODO
for循环功能 函数功能
单步执行效果图
直接执行效果图
源代码
//0 暂停 1 单步执行 2 断点
//创建枚举
var AstStatus = {
PAUSE : 0,
STEP :1,
BREAK : 2,
PASS:3
}
class ASTInterpreter {
constructor(ast,funcs) {
//执行状态,暂停 单步执行 断点
this.status = AstStatus.STEP;
//当前节点
this.currentBlock = null;
this.ast = ast;
this.variables = {};
this.userFuns={};
this.functions=new Set();
this.initVariables();
this.initFunc(funcs);
this.callback=console.log
}
addEventCallback(func){
this.callback=func
}
initFunc(funcs){
for (let item of funcs) {
this.addFunction(item)
}
}
initVariables() {
let vars = this.ast.variables;
for (let i = 0; i < vars.length; i++) {
const varDef = vars[i];
const varId = varDef.id;
const varName = varDef.name;
this.variables[varId] = varName;
}
}
stepFunc(){
this.executeBlock(this.currentBlock)
}
addFunction(key) {
this.functions.add(key);
}
getBlockType(block){
let type = block.type
if(this.functions.has(type)){
//说明是自定义函数
return 'function'
}else{
return type
}
}
execute() {
if (this.ast && this.ast.blocks && this.ast.blocks.blocks) {
const blocks = this.ast.blocks.blocks;
for (let i = 0; i < blocks.length; i++) {
const block = blocks[i];
this.executeBlock(block);
}
}
}
executeBlock(block) {
if (!block) return;
let btype=this.getBlockType(block)
let code = ''
switch (btype) {
case 'variables_set':
//变量id
const varId = block.fields.VAR.id;
//解析右值
const value = this.evaluateInput(block.inputs.VALUE.block);
code +=this.variables[varId]+'='+value;
break;
case 'function':
code += this.executeFunction(block);
break;
case 'controls_if':
this.executeIf(block);
break;
case 'procedures_callnoreturn':
this.executeCallNoReturn(block);
break;
case 'procedures_defnoreturn':
this.executeDefNoReturn(block);
break;
default:
console.error(`Unsupported block type: ${block.type}`);
}
if(code){
this.execLine(code,block.id)
}
// Execute next block
if (block.next && block.next.block) {
this.currentBlock = block.next.block;
if(this.status == AstStatus.STEP||this.status == AstStatus.PAUSE){
}else{
this.executeBlock(block.next.block);
}
}
}
//自定义函数定义 用户自己定义的函数不是系统的函数
executeDefNoReturn(block){
this.userFuns[block.fields.NAME]={
params:block.extraState.params,
block:block.inputs.STACK.block
}
return ''
}
//调用自定义函数 调用自己定义的函数
executeCallNoReturn(block){
//这里要隔离,不能影响其他变量,函数参数怎么传递,返回值怎么传递是个问题
let extraInfo = block.extraState
let name = extraInfo.name
let args = block.inputs
return ''
}
async executeIf(block) {
let extraInfo = block.extraState
let ifprefix = 'IF'
let doprefix = 'DO'
let isElse = false
let isEIf = false
if(extraInfo){
//说明有else
isElse=true
if(extraInfo.elseIfCount){
//说明有else if
isEIf = true
}
}
let idx=[0];
if(isEIf){
//extraInfo.elseIfCount是一个int类型,我要直线这个int类型的值
for (let i = 0; i < extraInfo.elseIfCount; i++) {
idx.push(i+1)
}
}
let isMatch = false
for (let i = 0; i < idx.length; i++) {
const index = idx[i];
const condition = await this.evaluateCondition(block.inputs[ifprefix + index].block)
if (condition) {
//满足条件执行对应分支
this.executeBlock(block.inputs[doprefix + index].block)
isMatch=true
break
}
}
//说明都不匹配 执行else block
if(isElse&&!isMatch){
this.executeBlock(block.inputs.ELSE.block)
}
return ''
}
executeFunction(block){
if (!block) return;
let funcName=block.type
let params=block.inputs
let paramArr=[]
for(let key in params){
let param=params[key]
if(param.block){
let paramValue=this.evaluateInput(param.block)
paramArr.push(paramValue)
}
}
//解析函数的参数名
//执行自定义函数
console.log(1,params)
return `${funcName}(${paramArr.join(',')})`
}
generateMixed(n) {
let chars = ['A','B','C','D','E','F','G','H','I','J','K','L','M',
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
let res = "";
for(let i = 0; i < n ; i++) {
let id = Math.floor(Math.random()*chars.length);
res += chars[id];
}
return res;
}
execLine(code,id){
//发送到服务器获取结果
//执行事件
this.callback({
id,
name:'call'
})
console.log('exec '+code)
}
async evaluateCondition(block){
if (!block) return;
let op = block.fields.OP
let left = this.evaluateInput(block.inputs.A.block)
let right = this.evaluateInput(block.inputs.B.block)
//发送到服务器获取结果
//随机生成变量,服务器会返回这个变量值,这个变量值是boolean类型
let key = this.generateMixed(5)
switch (op) {
case 'EQ':
op = '=='
break;
case 'NEQ':
op = '!='
break;
case 'LT':
op = '<'
break;
case 'LTE':
op = '<='
break;
case 'GT':
op = '>'
break;
case 'GTE':
op = '>='
break;
default:
console.error(`Unsupported condition operator: ${op}`);
break;
}
var code = `${key} = (${left} ${op} ${right})`
var id=block.id
await this.callback({
id,
name:'call'
})
console.log('eval '+code)
return true
}
evaluateInput(input) {
if (!input) return null;
let block = input;
let btype=this.getBlockType(block)
switch (btype) {
case 'text'://普通text 常量节点
return `'${block.fields.TEXT}'`;
case 'math_number':
return block.fields.NUM;
case 'variables_get'://变量赋值给变量
const varId = block.fields.VAR.id;
return this.variables[varId];//返回变量的名字
case 'function'://函数的返回值赋值给变量
return this.executeFunction(block); // Recursively execute custom types
default:
console.error(`Unsupported input block type: ${block.type}`);
return null;
}
}
}
// Example usage
var funs = ['create_mat','create_hobj','write_mat','printlog','test_tpl']
const interpreter = new ASTInterpreter(ast,funs);
interpreter.execute();