UNPKG

bloom-layout

Version:
310 lines (305 loc) 9.19 kB
var Mexp=require('./math_function.js'); function inc(arr,val){ for(var i=0;i<arr.length;i++) arr[i]+=val; return arr; } var token=['sin','cos','tan','pi','(',')','P','C', 'asin','acos','atan','7','8','9','int', 'cosh','acosh','ln','^','root','4','5','6','/','!', 'tanh','atanh','Mod','1','2','3','*', 'sinh','asinh','e','log','0','.','+','-',',','Sigma','n','Pi','pow']; var show=['sin','cos','tan','&pi;','(',')','P','C', 'asin','acos','atan','7','8','9','Int', 'cosh','acosh',' ln','^','root','4','5','6','&divide;','!', 'tanh','atanh',' Mod ','1','2','3','&times;', 'sinh','asinh','e',' log','0','.','+','-',',','&Sigma;','n','&Pi;','pow']; var eva=[Mexp.math.sin,Mexp.math.cos,Mexp.math.tan,'PI','(',')',Mexp.math.P,Mexp.math.C, Mexp.math.asin,Mexp.math.acos,Mexp.math.atan,'7','8','9',Math.floor, Mexp.math.cosh,Mexp.math.acosh,Math.log,Math.pow,Math.sqrt,'4','5','6',Mexp.math.div,Mexp.math.fact, Mexp.math.tanh,Mexp.math.atanh,Mexp.math.mod,'1','2','3',Mexp.math.mul, Mexp.math.sinh,Mexp.math.asinh,'E',Mexp.math.log,'0','.',Mexp.math.add,Mexp.math.sub,',',Mexp.math.sigma,'n',Mexp.math.Pi,Math.pow]; var preced={0:11,1:0,2:3,3:0,4:0,5:0,6:0,7:11,8:11,9:1,10:10,11:0,12:11,13:0}; var type=[0,0,0,3,4,5,10,10, 0,0,0,1,1,1,0, 0,0,0,10,0,1,1,1,2,7, 0,0,2,1,1,1,2, 0,0,3,0,1,6,9,9,11,12,13,12,8]; /* 0 : function with syntax function_name(Maths_exp) 1 : numbers 2 : binary operators like * / Mod left associate and same precedence 3 : Math constant values like e,pi,Cruncher ans 4 : opening bracket 5 : closing bracket 6 : decimal 7 : function with syntax (Math_exp)function_name 8: function with syntax function_name(Math_exp1,Math_exp2) 9 : binary operator like +,- 10: binary operator like P C or ^ 11: , 12: function with , seperated three parameters 13: variable of Sigma function */ var type0={0:true,1:true,3:true,4:true,6:true,8:true,9:true,12:true,13:true},//type2:true,type4:true,type9:true,type11:true,type21:true,type22 type1={0:true,1:true,2:true,3:true,4:true,5:true,6:true,7:true,8:true,9:true,10:true,11:true,12:true,13:true},//type3:true,type5:true,type7:true,type23 type_1={0:true,3:true,4:true,8:true,12:true,13:true}, empty={}, type_3={0:true,1:true,3:true,4:true,6:true,8:true,12:true,13:true},//type_5:true,type_7:true,type_23 type6={1:true}, newAr=[[], ["1","2","3","7","8","9","4","5","6","+","-","*","/","(",")","^","!","P","C","e","0",".",",","n"], ["pi","ln","Pi"], ["sin","cos","tan","Del","int","Mod","log","pow"], ["asin","acos","atan","cosh","root","tanh","sinh"], ["acosh","atanh","asinh","Sigma"]]; function match(str1,str2,i,x){ for(var f=0;f<x;f++){ if (str1[i+f]!==str2[f]) return false; } return true; } Mexp.addToken=function(tokens){ for(i=0;i<tokens.length;i++){ x=tokens[i].token.length; var temp=-1; //newAr is a specially designed data structure in which 1D array at location one of 2d array has all string with length 1 2 with 2 and so on if (x<newAr.length) //match to check if token is really huge and not existing //if not checked it will break in next line as undefined index for(y=0;y<newAr[x].length;y++){ if (tokens[i].token===newAr[x][y]){ temp=token.indexOf(newAr[x][y]); break; } } if (temp===-1) { token.push(tokens[i].token); type.push(tokens[i].type); if(newAr.length<=tokens[i].token.length) newAr[tokens[i].token.length]=[]; newAr[tokens[i].token.length].push(tokens[i].token); eva.push(tokens[i].value); show.push(tokens[i].show); } else { token[temp]=tokens[i].token; type[temp]=tokens[i].type; eva[temp]=tokens[i].value; show[temp]=tokens[i].show; } } }; Mexp.lex=function(inp,tokens){ 'use strict'; var str=[{type:4,value:"(",show:"(",pre:0}]; var ptc=[]; //Parenthesis to close at the beginning is after one token var inpStr=inp; var key; var pcounter=0; var allowed=type0; var bracToClose=0; var asterick=empty; var prevKey=''; var i,x,y; if(typeof tokens!=="undefined") Mexp.addToken(tokens); var obj={}; for(i=0;i<inpStr.length;i++){ if (inpStr[i]==' ') { continue; } key=''; sec:for(x=(inpStr.length-i>(newAr.length-2)?newAr.length-1:inpStr.length-i);x>0;x--){ for(y=0;y<newAr[x].length;y++){ if (match(inpStr,newAr[x][y],i,x)){ key=newAr[x][y]; break sec; } } } i+=key.length-1; if(key===''){ throw(new Mexp.exception("Can't understand after "+inpStr.slice(i))); } var index=token.indexOf(key); var cToken=key; var cType=type[index]; var cEv=eva[index]; var cPre=preced[cType]; var cShow=show[index]; var pre=str[str.length-1]; for(j=ptc.length;j--;){ //loop over ptc if(ptc[j]===0){ if([0,2,3,5,9,11,12,13].indexOf(cType)!==-1){ if(allowed[cType]!==true){ throw(new Mexp.exception(key+" is not allowed after "+prevKey)); } str.push({value:")",type:5,pre:0,show:")"}); allowed=type1; asterick=type_3; inc(ptc,-1).pop(); } } } if(allowed[cType]!==true){ throw(new Mexp.exception(key+" is not allowed after "+prevKey)); } if(asterick[cType]===true){ cType=2; cEv=Mexp.math.mul; cShow="&times;"; cPre=3; i=i-key.length; } obj={value:cEv,type:cType,pre:cPre,show:cShow}; if(cType===0){ allowed=type0; asterick=empty; inc(ptc,2).push(2); str.push(obj); str.push({value:"(",type:4,pre:0,show:"("}); } else if(cType===1){ if(pre.type===1){ pre.value+=cEv; inc(ptc,1); } else { str.push(obj); } allowed=type1; asterick=type_1; } else if(cType===2){ allowed=type0; asterick=empty; inc(ptc,2); str.push(obj); } else if(cType===3){//constant str.push(obj); allowed=type1; asterick=type_3; } else if(cType===4){ pcounter+=ptc.length; ptc=[]; bracToClose++; allowed=type0; asterick=empty; str.push(obj); } else if(cType===5){ if(!bracToClose){ throw(new Mexp.exception("Closing parenthesis are more than opening one, wait What!!!")); } while(pcounter--){ //loop over ptc str.push({value:")",type:5,pre:0,show:")"}); } pcounter=0; bracToClose--; allowed=type1; asterick=type_3; str.push(obj); } else if(cType===6){ if(pre.hasDec){ throw(new Mexp.exception("Two decimals are not allowed in one number")); } if(pre.type!==1){ pre={value:0,type:1,pre:0}; //pre needs to be changed as it will the last value now to be safe in later code str.push(pre); inc(ptc,-1); } allowed=type6; inc(ptc,1); asterick=empty; pre.value+=cEv; pre.hasDec=true; } else if(cType===7){ allowed=type1; asterick=type_3; inc(ptc,1); str.push(obj); } if(cType===8){ allowed=type0; asterick=empty; inc(ptc,4).push(4); str.push(obj); str.push({value:"(",type:4,pre:0,show:"("}); } else if(cType===9){ if(pre.type===9){ if(pre.value===Mexp.math.add){ pre.value=cEv; pre.show=cShow; inc(ptc,1); } else if(pre.value===Mexp.math.sub&&cShow==='-'){ pre.value=Mexp.math.add; pre.show='+'; inc(ptc,1); } } else if(pre.type!==5&&pre.type!==7&&pre.type!==1&&pre.type!==3&&pre.type!==13){//changesign only when negative is found if(cToken==='-'){//do nothing for + token //don't add with the above if statement as that will run the else statement of parent if on Ctoken + allowed=type0; asterick=empty; inc(ptc,2).push(2); str.push({value:Mexp.math.changeSign,type:0,pre:21,show:"-"}); str.push({value:"(",type:4,pre:0,show:"("}); } } else{ str.push(obj); inc(ptc,2); } allowed=type0; asterick=empty; } else if(cType===10){ allowed=type0; asterick=empty; inc(ptc,2); str.push(obj); } else if(cType===11){ allowed=type0; asterick=empty; str.push(obj); } else if(cType===12){ allowed=type0; asterick=empty; inc(ptc,6).push(6); str.push(obj); str.push({value:"(",type:4,pre:0}); } else if(cType===13){ allowed=type1; asterick=type_3; str.push(obj); } inc(ptc,-1); prevKey=key; } for(var j=ptc.length;j--;){ //loop over ptc if(ptc[j]===0){ str.push({value:")",show:")",type:5,pre:3}); inc(ptc,-1).pop(); } } if (allowed[5]!==true) { throw(new Mexp.exception("complete the expression")); } while(bracToClose--) str.push({value:")",show:")",type:5,pre:3}); str.push({type:5,value:")",show:")",pre:0}); // console.log(str); return new Mexp(str); }; module.exports=Mexp;