let Hemex = require("@saqut/hemex"); const File = require("./File"); /** * @param {File} file */ function ParseEngine(file) { let content = []; let buffer = []; let requiredImports = []; let hmx = new Hemex(); hmx.setText(file.content); function flushBuffer() { if(buffer.length) { content.push({ type:'text', value: buffer.join('') }); } buffer=[]; } hmx.addLexer({ name: "scope" },()=>{ hmx.while(()=>{ if(hmx.include('{{')) { let doubleBrackContent = hmx.gather('double-brack'); flushBuffer(); content.push({ type:'js-value', value: doubleBrackContent }); return true; }; if(hmx.include('@{')) { let jsBlockContent = hmx.gather('js-block'); flushBuffer(); content.push({ type:'js-block', value: jsBlockContent }); return true; }; if(hmx.include('@if(')) { let jsStatement = hmx.gather('js-if-block'); flushBuffer(); content.push({ type:'js-if-block', value: jsStatement }); return true; }; if(hmx.include('@endif', true)) { flushBuffer(); content.push({ type:'js-end-block' }); return true; }; if(hmx.include('@for(')) { let jsStatement = hmx.gather('js-for-block'); flushBuffer(); content.push({ type:'js-for-block', value: jsStatement }); return true; }; if(hmx.include('@import(', true)) { let importedThing = hmx.gather('import'); flushBuffer(); content.push({ type:'import', value: importedThing }); return true; }; if(hmx.include('@endfor', true)) { flushBuffer(); content.push({ type:'js-end-block' }); return true; }; buffer.push(hmx.getChar()); hmx.nextChar(); return true; }); flushBuffer(); }); hmx.addLexer({ name: "js-block" },() => { hmx.beginPosition(); if(hmx.include('@{')) { hmx.toChar(+2); }; let script = hmx.gather('readjscontent','}'); if(hmx.include('}')) { hmx.toChar(+1); }; hmx.acceptPosition(); return script; }) hmx.addLexer({ name: "double-brack" },()=>{ hmx.beginPosition(); if(hmx.include('{{')) { hmx.toChar(+2); }; let jsContent = hmx.gather('readjscontent', '}}'); if(hmx.include('}}')) { hmx.toChar(+2); }; hmx.acceptPosition(); return jsContent; }); hmx.addLexer({ name: "import" },()=>{ hmx.beginPosition(); if(hmx.include('@import(')) { hmx.toChar(+8); }; let jsContent = hmx.gather('readjscontent',')'); if(hmx.include(')')) { hmx.toChar(+1); }; hmx.acceptPosition(); return jsContent; }); hmx.addLexer({ name: "js-if-block" },()=>{ hmx.beginPosition(); if(hmx.include('@if(')) { hmx.toChar(+4); }; let jsContent = hmx.gather('readjscontent', ')'); if(hmx.include(')')) { hmx.toChar(+2); }; hmx.acceptPosition(); return jsContent; }); hmx.addLexer({ name: "js-for-block" },()=>{ hmx.beginPosition(); if(hmx.include('@for(')) { hmx.toChar(+5); }; let jsContent = hmx.gather('readjscontent', ')'); if(hmx.include(')')) { hmx.toChar(+1); }; hmx.acceptPosition(); return jsContent; }); hmx.addLexer({ name: "readjscontent" },(hmx, content)=>{ hmx.beginPosition(); let scopeLevel = 0; hmx.while(()=>{ if(scopeLevel == 0) { if(content == null) { if(hmx.isWhiteSpace()) { return false; } }else if(hmx.include(content)) { return false; } } switch(hmx.getChar()) { case '{':{ scopeLevel++; hmx.nextChar(); return true; } case '(':{ scopeLevel++; hmx.nextChar(); return true; } case '}':{ scopeLevel = Math.max(scopeLevel - 1, 0); hmx.nextChar(); return true; } case ')':{ scopeLevel = Math.max(scopeLevel - 1, 0); hmx.nextChar(); return true; } case '/':{ if(hmx.include('//')) throw new Error("Çift parantezlerde yorum satırı kullanılamaz") else hmx.gather('skip-regex-content'); return true; } case '\'': case '"': case '`':{ hmx.gather('skip-string-content',hmx.getChar()); return true; } default:{ hmx.nextChar(); return true; } }; }); let jscontent = hmx.getPositionRange(); hmx.acceptPosition(); return jscontent; }); hmx.addLexer({ name: "skip-string-content" },(hmx, char)=>{ hmx.beginPosition(); if(hmx.isChar(char)) { hmx.nextChar(); } hmx.while(()=>{ switch(hmx.getChar()) { case '\\':{ hmx.nextChar(); hmx.nextChar(); return true; } case char:{ hmx.nextChar(); return; } default:{ hmx.nextChar(); return true; } }; }); hmx.acceptPosition(); }); hmx.addLexer({ name: "skip-regex-content" },()=>{ hmx.beginPosition(); if(hmx.isChar('/')) { hmx.nextChar(); }; hmx.while(()=>{ switch(hmx.getChar()) { case '\\':{ hmx.nextChar(); hmx.nextChar(); return true; } case '/':{ hmx.nextChar(); return false; } default:{ return true; } }; }); hmx.acceptPosition(); }); hmx.gather('scope'); function useAST(content) { let jsContent = []; for (const { type, value } of content) switch(type) { case "js-value":{ jsContent.push(`output.push(${value});\n`); break; } case "js-block":{ jsContent.push(`\n${value}\n`); break; } case "text":{ jsContent.push(`output.push(${JSON.stringify(value)});\n`); break; } case "import":{ requiredImports.push(value); jsContent.push(`_external(${value});\n`); break; } case "js-if-block":{ jsContent.push(`if(${value}){\n`); break; } case "js-for-block":{ jsContent.push(`for(${value}){\n`); break; } case "js-endif-block":{ jsContent.push(`if(${value}){\n`); break; } case "js-end-block":{ jsContent.push(`\n};\n`); break; } } return jsContent.join(''); } return { ast:useAST(content), requiredImports }; }; module.exports = ParseEngine;