lowleveljs
Version:
1. 使用`@babel/parser`解析出js代码的语法树 2. 把所有的功能语句编译成最基础的操作指令列表 3. 编写解释器来运行这些基础操作指令
1,057 lines (973 loc) • 32.7 kB
JavaScript
const {CMDLS, NotSupport, mask, CMDLS_BIN_ext, CMDLS_FLOW_ext, CMDLS_SIG_ext, ARR_typ}=require('./common')
const [VAR, FUNC, FVAR, MOV, BIN, IF, ARR, CAL, TRY, FOR, FLOW, ATTR, OBJ, SWITCH, SIG, COPY, FARGU, LOG]=CMDLS
const [LGR, LSR, EQU, ADD, MULTI, SUB, DIV, AND, SEQU, SNEQU, OR, INSTANCEOF, IN, MOD, LSRE, LGRE, NEQU, BIT_MOV_LEFT, BIT_MOV_RIGHT, XOR, BIT_AND, BIT_OR, NO_SYMBOL_MOV_RIGHT]=CMDLS_BIN_ext
const [RET, THROW, BREAK, CONTINUE]=CMDLS_FLOW_ext
const [UNARY, TYPEOF, VOID, DELETE, INIT_THIS, BIT_NEGATE]=CMDLS_SIG_ext
const [ARR_ARRAY, ARR_MEMBER]=ARR_typ
// 类别枚举参考文档 https://github.com/babel/babel/blob/main/packages/babel-parser/ast/spec.md#programs
const CMDLS_map='VAR, FUNC, FVAR, MOV, BIN, IF, ARR, CAL, TRY, FOR, FLOW, ATTR, OBJ, SWITCH, SIG, COPY, FARGU, LOG'.split(/\s*,\s*/).reduce((a, b, i)=>{
a[b]=CMDLS[i]
return a
}, {})
let globalContextVars={}
function pack(maskarr, OUT4, MEM) {
let OUT5=[OUT4.length]
for(let i=0; i<OUT4.length; i++) {
OUT5.push(OUT4[i].length)
OUT5.push(...OUT4[i])
}
const mem=JSON.stringify([MEM, (x=>{
let ret=[]
for(let k in x) ret.push(parseInt(k), x[k])
return ret
})(globalContextVars)]).split('').map(a=>a.charCodeAt(0))
OUT5.push(mem.length)
OUT5.push(...mem)
let OUT6=[]
for(let i=0; i<OUT5.length; i++) {
if(!OUT5[i]) OUT6.push(0, 0, 0)
else if(OUT5[i]>255) {
OUT6.push(0, 0)
let o=[], n=0xff+1
for(let p=OUT5[i]; p>0; ) {
o.unshift(p%n)
p=(p-p%n)/n
}
OUT6.push(o.length, ...o)
}else{
OUT6.push(OUT5[i])
}
}
return mask(maskarr, OUT6)
/*
const mask=Math.round(0xff*Math.random())
return [mask, ...OUT6.map((a, i)=>a^((mask+i)%0xff))]
*/
}
// const a=idxMapper()
// a.getIdxOf(obj) // 返回下标数字
function idxMapper(o=0) {
let arr=[]
let map=new Map
return {
getIdxOf: v=>{
if(map.has(v)) return map.get(v)
let m=arr.length+o
map.set(v, m)
arr.push(v)
return m
},
getMap: _=>map,
getArr: _=>arr,
}
}
let ri=0
function rndstr() {
return (Math.random()+Date.now()).toString(36)+'_'+(ri++)
}
function find_val(contexts, val) {
// contexts[0]是特殊全局变量,不作为作用域
for(let j=contexts.length; j-->1; ) {
if(!contexts[j][val]) continue
return contexts[j][val]
}
}
function test_val(contexts, name) {
if(find_val(contexts, name)!==name) {
contexts[0][name]=name
}
return name
}
let _var_i=0, mvPrefix=rndstr(), cacheVars=[]
function mallocVar() {
if(!cacheVars.length) {
for(;cacheVars.length<1e3;) {
let v=mvPrefix+(_var_i++).toString(36)
cacheVars.push(v)
}
cacheVars.sort(_=>Math.random()-.5)
}
return cacheVars.pop()
}
let OUT=[]
const MEM_idxMapper=idxMapper() // 存放常值
function scanVariable(Node, context) {
if(Node.type==='VariableDeclaration') {
Node.declarations.map(({id, init})=>{
context[id.name]=id.name
})
}else if(Node.type==='FunctionDeclaration') {
context[Node.id.name]=Node.id.name
}
}
function parseNodeList(Node, contexts, ctx) {
if(!contexts) {
contexts=[{}, {}]
}
if(!ctx) {
ctx=contexts[contexts.length-1]
OUT.push({type: 'ctx', value: ctx})
ctx['this']='this'
OUT.push(`SIG this, ${INIT_THIS}, this`)
}
// 变量和function提升
for(let i=0; i<3; i++) {
Node.body.map(Node=>{
if(i===0) {
scanVariable(Node, ctx)
}else if(i===1) {
if(Node.type==='FunctionDeclaration') {
parseFunctionDeclaration(Node, contexts)
}
}else{
if(Node.type==='IfStatement') parseIfStatement(Node, contexts)
else if(Node.type==='VariableDeclaration') parseVariableDeclaration(Node, contexts)
else if(Node.type==='ReturnStatement') parseReturnStatement(Node, contexts)
else if(Node.type==='ExpressionStatement') parseExpressionStatement(Node, contexts)
else if(Node.type==='TryStatement') parseTryStatement(Node, contexts)
else if(Node.type==='ThrowStatement') parseThrowStatement(Node, contexts)
else if(Node.type==='ForStatement') parseForStatement(Node, contexts)
else if(Node.type==='BreakStatement') parseBreakStatement(Node, contexts)
else if(Node.type==='ContinueStatement') parseContinueStatement(Node, contexts)
else if(Node.type==='SwitchStatement') parseSwitchStatement(Node, contexts)
else if(Node.type==='ForInStatement') parseForInStatement(Node, contexts)
else if(Node.type==='BlockStatement') parseNodeList(Node, contexts, ctx)
else if(Node.type==='WhileStatement') parseWhileStatement(Node, contexts)
else if(Node.type==='EmptyStatement') ;
else if(Node.type!=='FunctionDeclaration') {
NotSupport(Node)
}
}
})
}
return contexts
}
function parseSwitchStatement(Node, contexts) {
const ctx=contexts[contexts.length-1]
const {discriminant, cases}=Node
let switch_flag=rndstr()
let jv=parseSideValue(discriminant, contexts)
OUT.push({type: 'switch', value: {switch_flag, jv}})
cases.map(Node=>{
if(Node.type==='SwitchCase') {
const {test, consequent}=Node
let caseVal
if(test===null) {
caseVal=jv
}else{
caseVal=parseSideValue(test, contexts)
}
OUT.push({type: 'switch', value: {switch_flag, caseVal}, extra: 'endcompare'})
parseNodeList({body: consequent}, contexts, ctx)
OUT.push({type: 'switch', value: {switch_flag}, extra: 'endcase'})
}else{
NotSupport(Node)
}
})
}
function parseFunctionDeclaration(Node, contexts, isClosure, closureRetVal) {
if(isClosure && !closureRetVal) {
NotSupport({
message: 'isClosure时,必须传入闭包指针'
})
}
function _parse() {
const ctx2={}
const {id, params, body}=Node
const fn=id.name
contexts[contexts.length-1][fn]=fn
const func_flag=rndstr()
OUT.push({type: 'func', value: {ctx: ctx2, refFn: fn, func_flag}})
let fvar_ls=[]
params.map((a, i)=>{
ctx2[a.name]=a.name
fvar_ls.push(a.name)
})
if(fvar_ls.length) {
OUT.push(`FVAR ${[...fvar_ls].join(', ')}`)
}
ctx2['arguments']='arguments'
ctx2['this']='this'
OUT.push(`FARGU arguments, this`)
parseNodeList(body, contexts.concat([ctx2]), ctx2)
OUT.push(`FLOW ${RET}`)
OUT.push({type: 'func', value: {func_flag}, extra: 'end_func'})
}
if(!isClosure) {
_parse()
return
}
contexts[contexts.length-1][closureRetVal]=closureRetVal
const ctx3={}
const fn=Node.id.name
ctx3[fn]=fn
contexts=contexts.concat([ctx3])
const func_flag=rndstr()
OUT.push({type: 'func', value: {ctx: ctx3, refFn: closureRetVal, func_flag}})
_parse()
OUT.push(`FLOW ${RET}, ${fn}`)
OUT.push({type: 'func', value: {func_flag}, extra: 'end_func'})
OUT.push(`CAL 0, ${closureRetVal}, ${closureRetVal}, ${MEM_idxMapper.getIdxOf(0)}`)
}
function parseBreakStatement(Node, contexts) {
OUT.push(`FLOW ${BREAK}`)
}
function parseContinueStatement(Node, contexts) {
OUT.push(`FLOW ${CONTINUE}`)
}
function parseConditionalExpression(Node, contexts, retVal) {
parseIfStatement(Node, contexts, retVal)
}
function parseIfStatement(Node, contexts, retVal) {
const {test, consequent, alternate}=Node
let jv=parseSideValue(test, contexts)
let if_flag=rndstr()
OUT.push({type: 'if', value: {if_flag, jv}})
if(consequent) {
let rv=parseSideValue(consequent, contexts, !retVal)
if(retVal) {
OUT.push(`MOV ${retVal}, ${rv}`)
}
}
OUT.push({type: 'if', value: {if_flag}, extra: 'else'})
if(alternate) {
let rv=parseSideValue(alternate, contexts, !retVal)
if(retVal) {
OUT.push(`MOV ${retVal}, ${rv}`)
}
}
OUT.push({type: 'if', value: {if_flag}, extra: 'endif'})
}
function parseForInStatement(Node, contexts) {
parseForStatement(Node, contexts)
}
function parseWhileStatement(Node, contexts) {
parseForStatement(Node, contexts)
}
function parseSideValue(Node, contexts, noRetVal, opts={}) {
let retVal=noRetVal? 0: mallocVar()
const ctx=contexts[contexts.length-1]
if(Node===null) {
Node={
type: 'Identifier',
name: 'undefined',
}
}
if(Node.type==='UpdateExpression') {
parseUpdateExpression(Node, contexts, retVal)
}else if(Node.type==='VariableDeclaration') {
scanVariable(Node, ctx)
parseVariableDeclaration(Node, contexts)
}else if(Node.type==='AssignmentExpression') {
retVal=parseAssignmentExpression(Node, contexts)
}else if(Node.type==='NumericLiteral') {
if(retVal) {
OUT.push(`MOV ${retVal}, ${MEM_idxMapper.getIdxOf(Node.value)}`)
}
}else if(Node.type==='ObjectExpression') {
parseObjectExpression(Node, contexts, retVal || mallocVar())
}else if(Node.type==='CallExpression') {
parseCallExpression(Node, contexts, retVal || mallocVar())
}else if(Node.type==='MemberExpression') {
parseMemberExpression(Node, contexts, retVal || mallocVar())
if(retVal && !opts.noAttr) OUT.push(`ATTR ${retVal}`)
}else if(Node.type==='FunctionExpression') {
parseFunctionExpression(Node, contexts, retVal || mallocVar())
}else if(Node.type==='BinaryExpression') {
parseBinaryExpression(Node, contexts, retVal || mallocVar())
}else if(Node.type==='LogicalExpression') {
parseLogicalExpression(Node, contexts, retVal || mallocVar())
}else if(Node.type==='UnaryExpression') {
parseUnaryExpression(Node, contexts, retVal)
}else if(Node.type==='NewExpression') {
parseNewExpression(Node, contexts, retVal || mallocVar())
}else if(Node.type==='BooleanLiteral') {
if(retVal) {
OUT.push(`MOV ${retVal}, ${MEM_idxMapper.getIdxOf(Node.value)}`)
}
}else if(Node.type==='Identifier') {
retVal=test_val(contexts, Node.name)
}else if(Node.type==='ConditionalExpression') {
parseConditionalExpression(Node, contexts, retVal)
}else if(Node.type==='ArrayExpression') {
parseArrayExpression(Node, contexts, retVal || mallocVar())
}else if(Node.type==='StringLiteral') {
if(retVal) {
OUT.push(`MOV ${retVal}, ${MEM_idxMapper.getIdxOf(Node.value)}`)
}
}else if(Node.type==='SequenceExpression') {
parseSequenceExpression(Node, contexts, retVal || mallocVar())
}else if(Node.type==='ThisExpression') {
if(retVal) {
OUT.push(`MOV ${retVal}, this`)
}
}else if(Node.type==='ContinueStatement') {
parseContinueStatement(Node, contexts)
}else if(Node.type==='BreakStatement') {
parseBreakStatement(Node, contexts)
}else if(Node.type==='ThrowStatement') {
parseThrowStatement(Node, contexts)
}else if(Node.type==='BlockStatement') {
parseNodeList(Node, contexts, ctx)
}else if(Node.type==='ReturnStatement') {
parseReturnStatement(Node, contexts)
}else if(Node.type==='IfStatement') {
parseIfStatement(Node, contexts, retVal)
}else if(Node.type==='ExpressionStatement') {
parseExpressionStatement(Node, contexts)
}else if(Node.type==='ForInStatement') {
parseForInStatement(Node, contexts)
}else if(Node.type==='RegExpLiteral') {
parseRegExpLiteral(Node, contexts, retVal)
}else if(Node.type==='EmptyStatement') {
// EmptyStatement 什么都不做
}else if(Node.type==='SwitchStatement') {
parseSwitchStatement(Node, contexts)
}else if(Node.type==='NullLiteral') {
if(retVal) {
OUT.push(`MOV ${retVal}, ${MEM_idxMapper.getIdxOf(null)}`)
}
}else if(Node.type==='ForStatement') {
parseForStatement(Node, contexts)
}else if(Node.type==='TryStatement') {
parseTryStatement(Node, contexts)
}else{
NotSupport(Node)
}
return retVal
}
function parseForStatement(Node, contexts) {
/**
for循环没有自己的ctx,init变量和外层的同级,内部的也是和外层变量同级
*/
// const ctx=contexts[contexts.length-1]
const {
type,
init, test, update,
left, right,
body,
}=Node
const fortestval=mallocVar()
const for_flag=rndstr()
let _next=0
if(type==='ForStatement' || type==='WhileStatement') {
if(init) {
parseSideValue(init, contexts, 1)
}
OUT.push({type: 'for', value: {for_flag, fortestval}})
if(!test) {
OUT.push(`MOV ${fortestval}, ${MEM_idxMapper.getIdxOf(1)}`)
}else{
let tv=parseSideValue(test, contexts)
OUT.push(`MOV ${fortestval}, ${tv}`)
}
OUT.push({type: 'for', value: {for_flag}, extra: 'endtest'})
if(update) {
parseSideValue(update, contexts, 1)
}
OUT.push({type: 'for', value: {for_flag}, extra: 'endupdate'})
}else if(type==='ForInStatement') {
/**
for(k in x) {...}
等价于
if(x) {
for(i=0, ls=Object.keys(x); i<ls.length; i++) {
k=x[i]
...
}
}
*/
let bind_key
if(left.type==='Identifier') {
bind_key=test_val(contexts, left.name)
}else if(left.type==='VariableDeclaration') {
scanVariable(left, contexts[contexts.length-1])
parseVariableDeclaration(left, contexts)
if(left.declarations.length!==1) {
NotSupport(left)
}
bind_key=test_val(contexts, left.declarations[0].id.name)
}else{
NotSupport(left)
}
let loop_val=parseSideValue(right, contexts)
let if_flag=rndstr()
OUT.push({type: 'if', value: {
if_flag,
jv: loop_val,
}})
_next=_=>{
OUT.push({type: 'if', value: {
if_flag,
}, extra: 'else'})
OUT.push({type: 'if', value: {
if_flag,
}, extra: 'endif'})
}
const i=mallocVar(), ls=mallocVar()
OUT.push(`MOV ${i}, ${MEM_idxMapper.getIdxOf(0)}`)
let fn=mallocVar(), arg=mallocVar(), key_len=mallocVar()
OUT.push(`MOV ${fn}, ${MEM_idxMapper.getIdxOf(0)}`)
OUT.push(`MOV ${arg}, ${MEM_idxMapper.getIdxOf(0)}`)
OUT.push(`MOV ${key_len}, ${MEM_idxMapper.getIdxOf(0)}`)
OUT.push(`ARR ${fn}, ${ARR_ARRAY}, ${test_val(contexts, 'Object')}, ${MEM_idxMapper.getIdxOf('keys')}`)
OUT.push(`ARR ${arg}, ${ARR_ARRAY}, ${loop_val}`)
OUT.push(`CAL 0, ${ls}, ${fn}, ${arg}`)
OUT.push(`ARR ${key_len}, ${ARR_MEMBER}, ${ls}, ${MEM_idxMapper.getIdxOf('length')}`)
OUT.push(`ATTR ${key_len}`)
OUT.push(`MOV ${bind_key}, ${MEM_idxMapper.getIdxOf(0)}`)
OUT.push({type: 'for', value: {
for_flag,
fortestval,
}})
OUT.push(`BIN ${fortestval}, ${LSR}, ${i}, ${key_len}`)
OUT.push({type: 'for', value: {
for_flag,
}, extra: 'endtest'})
OUT.push(`BIN ${i}, ${ADD}, ${i}, ${MEM_idxMapper.getIdxOf(1)}`)
OUT.push({type: 'for', value: {
for_flag,
}, extra: 'endupdate'})
OUT.push(`MOV ${bind_key}, ${MEM_idxMapper.getIdxOf(0)}`)
OUT.push(`ARR ${bind_key}, ${ARR_MEMBER}, ${ls}, ${i}`)
OUT.push(`ATTR ${bind_key}`)
}else{
NotSupport(Node)
}
if(body) {
parseSideValue(body, contexts, 1)
}
OUT.push({type: 'for', value: {
for_flag,
}, extra: 'endfor'})
if(_next) _next()
}
function parseSequenceExpression(Node, contexts, ret) {
const {expressions}=Node
expressions.map((Node, i)=>{
let retVal=i===expressions.length-1? ret: undefined
let rv=parseSideValue(Node, contexts)
if(retVal) {
OUT.push(`MOV ${retVal}, ${rv}`)
}
})
}
function parseReturnStatement(Node, contexts) {
const {argument}=Node
if(!argument) {
OUT.push(`FLOW ${RET}`)
}else{
OUT.push(`FLOW ${RET}, ${parseSideValue(argument, contexts)}`)
}
}
function parseLogicalExpression(Node, contexts, retVal) {
parseBinaryExpression(Node, contexts, retVal)
}
function parseFunctionExpression(Node, contexts, retVal) {
const rv=mallocVar()
Node.id=Node.id || {name: mallocVar()}
const closureRetVal=mallocVar()
parseFunctionDeclaration(Node, contexts, 1, closureRetVal)
OUT.push(`MOV ${retVal}, ${closureRetVal}`)
}
function parseBinaryExpression(Node, contexts, retVal) {
const {left, operator, right}=Node
OUT.push(`MOV ${retVal}, ${parseSideValue(left, contexts)}`)
let retVal2=mallocVar()
if(operator==='&&') {
let if_flag=rndstr()
OUT.push({type: 'if', value: {
if_flag,
jv: retVal,
}})
OUT.push(`MOV ${retVal2}, ${parseSideValue(right, contexts)}`)
OUT.push({type: 'if', value: {
if_flag,
}, extra: 'else'})
OUT.push(`MOV ${retVal2}, ${retVal}`)
OUT.push({type: 'if', value: {
if_flag,
}, extra: 'endif'})
}else if(operator==='||') {
let if_flag=rndstr()
OUT.push({type: 'if', value: {
if_flag,
jv: retVal,
}})
OUT.push(`MOV ${retVal2}, ${retVal}`)
OUT.push({type: 'if', value: {
if_flag,
}, extra: 'else'})
OUT.push(`MOV ${retVal2}, ${parseSideValue(right, contexts)}`)
OUT.push({type: 'if', value: {
if_flag,
}, extra: 'endif'})
}else{
OUT.push(`MOV ${retVal2}, ${parseSideValue(right, contexts)}`)
}
if(operator==='*') {
OUT.push(`BIN ${retVal}, ${MULTI}, ${retVal}, ${retVal2}`)
}else if(operator==='/') {
OUT.push(`BIN ${retVal}, ${DIV}, ${retVal}, ${retVal2}`)
}else if(operator==='+') {
OUT.push(`BIN ${retVal}, ${ADD}, ${retVal}, ${retVal2}`)
}else if(operator==='-') {
OUT.push(`BIN ${retVal}, ${SUB}, ${retVal}, ${retVal2}`)
}else if(operator==='<') {
OUT.push(`BIN ${retVal}, ${LSR}, ${retVal}, ${retVal2}`)
}else if(operator==='>') {
OUT.push(`BIN ${retVal}, ${LGR}, ${retVal}, ${retVal2}`)
}else if(operator==='==') {
OUT.push(`BIN ${retVal}, ${EQU}, ${retVal}, ${retVal2}`)
}else if(operator==='&&') {
OUT.push(`BIN ${retVal}, ${AND}, ${retVal}, ${retVal2}`)
}else if(operator==='===') {
OUT.push(`BIN ${retVal}, ${SEQU}, ${retVal}, ${retVal2}`)
}else if(operator==='!==') {
OUT.push(`BIN ${retVal}, ${SNEQU}, ${retVal}, ${retVal2}`)
}else if(operator==='||') {
OUT.push(`BIN ${retVal}, ${OR}, ${retVal}, ${retVal2}`)
}else if(operator==='instanceof') {
OUT.push(`BIN ${retVal}, ${INSTANCEOF}, ${retVal}, ${retVal2}`)
}else if(operator==='in') {
OUT.push(`BIN ${retVal}, ${IN}, ${retVal}, ${retVal2}`)
}else if(operator==='%') {
OUT.push(`BIN ${retVal}, ${MOD}, ${retVal}, ${retVal2}`)
}else if(operator==='<=') {
OUT.push(`BIN ${retVal}, ${LSRE}, ${retVal}, ${retVal2}`)
}else if(operator==='>=') {
OUT.push(`BIN ${retVal}, ${LGRE}, ${retVal}, ${retVal2}`)
}else if(operator==='!=') {
OUT.push(`BIN ${retVal}, ${NEQU}, ${retVal}, ${retVal2}`)
}else if(operator==='<<') {
OUT.push(`BIN ${retVal}, ${BIT_MOV_LEFT}, ${retVal}, ${retVal2}`)
}else if(operator==='>>') {
OUT.push(`BIN ${retVal}, ${BIT_MOV_RIGHT}, ${retVal}, ${retVal2}`)
}else if(operator==='^') {
OUT.push(`BIN ${retVal}, ${XOR}, ${retVal}, ${retVal2}`)
}else if(operator==='|') {
OUT.push(`BIN ${retVal}, ${BIT_OR}, ${retVal}, ${retVal2}`)
}else if(operator==='&') {
OUT.push(`BIN ${retVal}, ${BIT_AND}, ${retVal}, ${retVal2}`)
}else if(operator==='>>>') {
OUT.push(`BIN ${retVal}, ${NO_SYMBOL_MOV_RIGHT}, ${retVal}, ${retVal2}`)
}else{
NotSupport(operator)
}
}
function parseThrowStatement(Node, contexts) {
const {argument}=Node
OUT.push(`FLOW ${THROW}, ${parseSideValue(argument, contexts)}`)
}
function parseUpdateExpression(Node, contexts, retVal) {
const {operator, prefix, argument}=Node
if(!prefix && retVal) {
const arg={left: argument, __keep: 1}
let lv=parseAssignmentExpression(arg, contexts)
OUT.push(`ATTR ${lv}`)
OUT.push(`MOV ${retVal}, ${lv}`)
}
const arg={left: argument}
if(operator==='++') {
arg.operator='+='
arg.right={type: 'NumericLiteral', value: 1}
}else if(operator==='--') {
arg.operator='-='
arg.right={type: 'NumericLiteral', value: 1}
}else{
NotSupport(operator)
}
let lv=parseAssignmentExpression(arg, contexts)
if(prefix && retVal) {
OUT.push(`MOV ${retVal}, ${lv}`)
}
}
function parseTryStatement(Node, contexts) {
const ctx=contexts[contexts.length-1]
const {block, handler, finalizer}=Node
let try_flag=rndstr()
OUT.push({type: 'try', value: {
try_flag,
param: handler? handler.param.name: 0, // handler.param 是 catch的变量
}})
parseNodeList(block, contexts, ctx)
OUT.push({type: 'try', value: {
try_flag,
}, extra: 'catch'})
if(handler) {
let ctx2={[handler.param.name]: handler.param.name}
parseNodeList(handler.body, contexts.concat([ctx2]), ctx2)
}
OUT.push({type: 'try', value: {
try_flag,
}, extra: 'finally'})
if(finalizer) {
parseNodeList(finalizer, contexts, ctx)
}
OUT.push({type: 'try', value: {
try_flag,
}, extra: 'endtry'})
}
function parseExpressionStatement(Node, contexts) {
parseSideValue(Node.expression, contexts)
}
function parseAssignmentExpression(Node, contexts) {
const {left, __keep, operator, right}=Node
let lv, is_addr=1
if(left.type==='Identifier') {
for(let i=contexts.length; i-->0; ) {
if(i===0 || contexts[i][left.name]) {
contexts[i][left.name]=contexts[i][left.name] || left.name
}
}
lv=left.name
is_addr=0
}else if(left.type==='MemberExpression') {
lv=mallocVar()
parseMemberExpression(left, contexts, lv)
}else{
NotSupport(left)
}
// 用于 UpdateExpression 后置的场景
if(__keep) {
return lv
}
let rv=parseSideValue(right, contexts)
let qv=mallocVar()
if(operator==='=') {
OUT.push(`MOV ${qv}, ${rv}`)
}else if(operator==='+=') {
OUT.push(`BIN ${qv}, ${ADD}, ${lv}, ${rv}`)
}else if(operator==='-=') {
OUT.push(`BIN ${qv}, ${SUB}, ${lv}, ${rv}`)
}else if(operator==='*=') {
OUT.push(`BIN ${qv}, ${MULTI}, ${lv}, ${rv}`)
}else if(operator==='/=') {
OUT.push(`BIN ${qv}, ${DIV}, ${lv}, ${rv}`)
}else if(operator==='<<=') {
OUT.push(`BIN ${qv}, ${BIT_MOV_LEFT}, ${lv}, ${rv}`)
}else if(operator==='>>=') {
OUT.push(`BIN ${qv}, ${BIT_MOV_RIGHT}, ${lv}, ${rv}`)
}else if(operator==='^=') {
OUT.push(`BIN ${qv}, ${XOR}, ${lv}, ${rv}`)
}else if(operator==='|=') {
OUT.push(`BIN ${qv}, ${BIT_OR}, ${lv}, ${rv}`)
}else if(operator==='&=') {
OUT.push(`BIN ${qv}, ${BIT_AND}, ${lv}, ${rv}`)
}else{
NotSupport(operator)
}
if(is_addr) {
OUT.push(`COPY ${lv}, ${qv}`)
OUT.push(`ATTR ${lv}`)
}else{
OUT.push(`MOV ${lv}, ${qv}`)
}
return lv
}
function parseObjectExpression(Node, contexts, ret) {
OUT.push(`MOV ${ret}, ${MEM_idxMapper.getIdxOf(0)}`)
Node.properties.map(Node=>{
if(Node.type==='ObjectProperty') {
parseObjectProperty(Node, contexts, ret)
}else{
NotSupport(Node)
}
})
if(!Node.properties.length) {
OUT.push(`OBJ ${ret}`)
}
}
function parseObjectProperty(Node, contexts, ret) {
const {key, value}=Node
if(key.type==='Identifier') {
key.type='StringLiteral'
key.value=key.name
}
let keyVal=parseSideValue(key, contexts)
let valueVal=parseSideValue(value, contexts)
OUT.push(`OBJ ${ret}, ${keyVal}, ${valueVal}`)
}
function parseUnaryExpression(Node, contexts, retVal) {
const {operator, argument}=Node
if(operator==='delete') {
if(argument.type==='MemberExpression') {
let lv=mallocVar()
parseMemberExpression(argument, contexts, lv)
OUT.push(`SIG ${retVal}, ${DELETE}, ${lv}`)
}else{
NotSupport(argument)
}
return
}
let jv=parseSideValue(argument, contexts)
if(operator==='!') {
OUT.push(`SIG ${retVal}, ${UNARY}, ${jv}`)
}else if(operator==='typeof') {
OUT.push(`SIG ${retVal}, ${TYPEOF}, ${jv}`)
}else if(operator==='void') {
OUT.push(`SIG ${retVal}, ${VOID}, ${jv}`)
}else if(operator==='-') {
OUT.push(`BIN ${retVal}, ${SUB}, ${MEM_idxMapper.getIdxOf(0)}, ${jv}`)
}else if(operator==='+') {
OUT.push(`BIN ${retVal}, ${MULTI}, ${MEM_idxMapper.getIdxOf(1)}, ${jv}`)
}else if(operator==='~') {
OUT.push(`SIG ${retVal}, ${BIT_NEGATE}, ${jv}`)
}else{
NotSupport(operator)
}
}
function parseNewExpression(Node, contexts, ret) {
parseCallExpression(Node, contexts, ret, 1)
}
function parseCallExpression(Node, contexts, retVal, isNew) {
const ctx=contexts[contexts.length-1]
const {callee, arguments}=Node
let fn=parseSideValue(callee, contexts, 0, {noAttr: 1})
let arg=mallocVar(), arr=[]
if(arguments && arguments.length) {
arguments.map((Node, i)=>{
arr.push(parseSideValue(Node, contexts))
})
}
OUT.push(`MOV ${arg}, ${MEM_idxMapper.getIdxOf(0)}`)
OUT.push(`ARR ${[arg, ARR_ARRAY, ...arr].join(', ')}`)
retVal=retVal || mallocVar()
ctx[retVal]=retVal
OUT.push(`CAL ${isNew? 1: 0}, ${retVal}, ${fn}, ${arg}`)
}
function parseArrayExpression(Node, contexts, retVal) {
OUT.push(`MOV ${retVal}, ${MEM_idxMapper.getIdxOf(0)}`)
let arr=[]
Node.elements.map(Node=>{
arr.push(parseSideValue(Node, contexts))
})
OUT.push(`ARR ${[retVal, ARR_ARRAY, ...arr].join(', ')}`)
}
function parseMemberExpression(Node, contexts, retVal) {
const ctx=contexts[contexts.length-1]
const {object, computed, property}=Node
OUT.push(`MOV ${retVal}, ${MEM_idxMapper.getIdxOf(0)}`)
OUT.push(`ARR ${retVal}, ${ARR_MEMBER}`)
OUT.push(`ARR ${retVal}, ${parseSideValue(object, contexts)}`)
ctx[retVal]=retVal
if(property.type==='Identifier' && !computed) {
property.type='StringLiteral'
property.value=property.name
}
let prop=parseSideValue(property, contexts)
OUT.push(`ARR ${retVal}, ${prop}`)
}
function parseVariableDeclaration(Node, contexts) {
const ctx=contexts[contexts.length-1]
Node.declarations.map(({id, init})=>{
if(!init) return;
let jv=parseSideValue(init, contexts)
OUT.push(`MOV ${test_val(contexts, id.name)}, ${jv}`)
})
}
function parseRegExpLiteral(Node, contexts, ret) {
const {pattern, flags}=Node
const fn=mallocVar(), arg=mallocVar()
OUT.push(`MOV ${arg}, ${MEM_idxMapper.getIdxOf(0)}`)
OUT.push(`ARR ${arg}, ${ARR_ARRAY}, ${MEM_idxMapper.getIdxOf(pattern)}, ${MEM_idxMapper.getIdxOf(flags)}`)
OUT.push(`MOV ${fn}, ${test_val(contexts, 'RegExp')}`)
OUT.push(`CAL 1, ${ret}, ${fn}, ${arg}`)
}
function compile(code, maskarr) {
let p=require("@babel/parser").parse(code)
let contexts=parseNodeList(p.program)
const MEM=MEM_idxMapper.getArr()
// 优化指令
let OUT_tmp, i
// 1. 前后相同的 MOV x, y 去掉连续的后面一行
i=0, OUT_tmp=[]
for(let ls; i<OUT.length; i++) {
if(OUT[1].constructor===String && ls===OUT[i] && ['MOV'].indexOf(OUT[i].split(/[\s,]+/)[0])>-1) {
continue
}
ls=OUT[i]
OUT_tmp.push(ls)
}
OUT=OUT_tmp
// 2. 对同一个变量赋值ARR合并成一句
i=0, OUT_tmp=[]
for(; i<OUT.length; i++) {
if(!i || OUT[i-1].constructor!==String || OUT[i].constructor!==String) {
OUT_tmp.push(OUT[i])
continue
}
const r0=OUT[i-1].split(/[\s,]+/)
const r1=OUT[i].split(/[\s,]+/)
if(r0[0]===r1[0] && r0[0]==='ARR' && r0[1]===r1[1]) {
OUT_tmp[OUT_tmp.length-1]+=' '+r1.slice(2).join(', ')
}else{
OUT_tmp.push(OUT[i])
}
}
OUT=OUT_tmp
// 3. 对同一个变量赋值OBJ合并成一句
i=0, OUT_tmp=[]
for(; i<OUT.length; i++) {
if(!i || OUT[i-1].constructor!==String || OUT[i].constructor!==String) {
OUT_tmp.push(OUT[i])
continue
}
const r0=OUT[i-1].split(/[\s,]+/)
const r1=OUT[i].split(/[\s,]+/)
if(r0[0]===r1[0] && r0[0]==='OBJ' && r0[1]===r1[1]) {
OUT_tmp[OUT_tmp.length-1]+=' '+r1.slice(2).join(', ')
}else{
OUT_tmp.push(OUT[i])
}
}
OUT=OUT_tmp
// 4. 对连续MOV语句合并成一句
i=0, OUT_tmp=[]
for(let mv=[], _mv=mv=>{
if(mv.length) {
OUT_tmp.push(`MOV `+mv.reduce((a, b)=>{
a[0]+=', '+b[0]
a[1]+=', '+b[1]
return a
}).join(', '))
}
mv.splice(0)
}; i<OUT.length; i++) {
if(OUT[i].constructor!==String) {
_mv(mv)
OUT_tmp.push(OUT[i])
continue
}
const r=OUT[i].split(/[\s,]+/)
if(r[0]==='MOV') {
mv.push(r.slice(1))
}else{
_mv(mv)
OUT_tmp.push(OUT[i])
}
}
OUT=OUT_tmp
// 把ctx转为VAR
let OUT2=[]
OUT.map((x, i)=>{
if(typeof x!=='object') {
OUT2.push(x)
}else if(x.type==='ctx') {
const fv=Object.values(x.value).filter(a=>typeof a!=='object')
if(fv.length) {
OUT2.push(`VAR ${fv.join(', ')}`)
}
}else if(x.type==='func') {
if(x.extra!=='end_func') {
x.value.beginLine=OUT2.length
OUT2.push(x)
const fv1=Object.values(x.value.ctx)
if(fv1.length) {
OUT2.push(`VAR ${fv1.join(', ')}`)
}
}else{
let f=OUT2.find(a=>a.type==='func' && a.value.func_flag===x.value.func_flag && !a.extra)
f.value.endLine=OUT2.length
}
}else if(x.type==='if') {
if(!x.extra) {
x.value.beginLine=OUT2.length
OUT2.push(x)
}else if(x.extra==='else') {
let f=OUT2.find(a=>a.type==='if' && a.value.if_flag===x.value.if_flag && !a.extra)
f.value.elseLine=OUT2.length
}else if(x.extra==='endif') {
let f=OUT2.find(a=>a.type==='if' && a.value.if_flag===x.value.if_flag && !a.extra)
f.value.endLine=OUT2.length
}
}else if(x.type==='try') {
if(!x.extra) {
x.value.beginLine=OUT2.length
OUT2.push(x)
}else if(x.extra==='catch') {
let f=OUT2.find(a=>a.type==='try' && a.value.try_flag===x.value.try_flag && !a.extra)
f.value.catchLine=OUT2.length
}else if(x.extra==='finally') {
let f=OUT2.find(a=>a.type==='try' && a.value.try_flag===x.value.try_flag && !a.extra)
f.value.finallyLine=OUT2.length
}else if(x.extra==='endtry') {
let f=OUT2.find(a=>a.type==='try' && a.value.try_flag===x.value.try_flag && !a.extra)
f.value.endLine=OUT2.length
}
}else if(x.type==='for') {
if(!x.extra) {
x.value.beginLine=OUT2.length
OUT2.push(x)
}else if(x.extra==='endtest') {
let f=OUT2.find(a=>a.type==='for' && a.value.for_flag===x.value.for_flag && !a.extra)
f.value.testedLine=OUT2.length
}else if(x.extra==='endupdate') {
let f=OUT2.find(a=>a.type==='for' && a.value.for_flag===x.value.for_flag && !a.extra)
f.value.updatedLine=OUT2.length
}else if(x.extra==='endfor') {
let f=OUT2.find(a=>a.type==='for' && a.value.for_flag===x.value.for_flag && !a.extra)
f.value.endLine=OUT2.length
}
}else if(x.type==='switch') {
if(!x.extra) {
x.value.beginLine=OUT2.length
x.value.casesValueLine=[]
OUT2.push(x)
}else if(x.extra==='endcompare') {
let f=OUT2.find(a=>a.type==='switch' && a.value.switch_flag===x.value.switch_flag && !a.extra)
f.value.casesValueLine.push(OUT2.length, x.value.caseVal)
}else if(x.extra==='endcase') {
let f=OUT2.find(a=>a.type==='switch' && a.value.switch_flag===x.value.switch_flag && !a.extra)
f.value.casesValueLine.push(OUT2.length)
}
}
})
// 处理行数
let OUT3=[]
for(let i=0; i<OUT2.length; i++) {
const x=OUT2[i]
if(typeof x!=='object') {
OUT3.push(x)
}else if(x.type==='func') {
OUT3.push(`FUNC ${x.value.refFn}, ${x.value.endLine}`)
}else if(x.type==='if') {
OUT3.push(`IF ${x.value.jv}, ${x.value.elseLine}, ${x.value.endLine}`)
}else if(x.type==='try') {
OUT3.push(`TRY ${x.value.param}, ${x.value.catchLine}, ${x.value.finallyLine}, ${x.value.endLine}`)
}else if(x.type==='for') {
OUT3.push(`FOR ${x.value.fortestval}, ${x.value.testedLine}, ${x.value.updatedLine}, ${x.value.endLine}`)
}else if(x.type==='switch') {
OUT3.push(`SWITCH ${[x.value.jv, ...x.value.casesValueLine].join(', ')}`)
}else{
NotSupport(x)
}
}
// 变量名替换成MEM虚拟下标
const VAR_idxMapper=idxMapper(MEM_idxMapper.getArr().length)
const OUT4=OUT3.map(a=>a.split(/[\s,]+/).map((a, i)=>{
if(!i) return CMDLS_map[a]
if(parseInt(a)+''===a) return a*1
return VAR_idxMapper.getIdxOf(a)
}))
for(let key in contexts[0]) {
globalContextVars[VAR_idxMapper.getIdxOf(key)]=key
}
// 打包成序列
const OUT6=pack(maskarr, OUT4, MEM)
return {
TXT: OUT3.map((a, i)=>`${(i+1+'').padStart(3, ' ')}. ${(_=>{
_=_.replace(new RegExp('(^| )'+mvPrefix, 'g'), '$1X')
const [cmd, ...vals]=_.split(/[\s,]+/)
return cmd+' '+vals.map((a, i)=>{
if(parseInt(a)+''===a && +a<MEM.length) return JSON.stringify(MEM[+a])
return '['+a+']'
}).join(', ')
})(a)}`).join('\n'),
MEM: JSON.stringify(MEM),
GVARS: JSON.stringify(globalContextVars),
SEQ: OUT4.map((a, i)=>`${i+1}. ${a.join(' ')}`).join('\n'),
BIN: OUT6,
}
}
module.exports=compile