export default function Hemex() { }; Hemex.EOL = "\n"; /** * Hemex variable white space chars * @type {Number[]} */ Hemex.WhiteSpace = [ 9,10,11,12,13,32,133 ]; /** * Current cursor position * @type {Number} */ Hemex.prototype.offset = 0; /** * Mapping offset points * @type {Number[]} */ Hemex.prototype.offsetMap = []; Hemex.prototype.beginPosition = function(){ this.offsetMap.push( this.getLastPosition() ) } /** * Adding current position to offset map */ Hemex.prototype.acceptPosition = function(){ let t = this.offsetMap.pop(); this.setLastPosition(t) } /** * Get text range current and parent offsets * @returns {[Number,Number]} */ Hemex.prototype.positionRange = function(){ let len = this.offsetMap.length; if(len == 0) { return [0,this.offset] }else if(len == 1){ return [this.offset,this.offsetMap[len - 1]] }else{ return [this.offsetMap[len - 2],this.offsetMap[len - 1]] } } /** * Get text range between current offset and parent offset * @returns {String} */ Hemex.prototype.getPositionRange = function(){ let u = this.positionRange(); return this.text.slice(u[0],u[1]) } /** * Cancel current position and return to parent offset */ Hemex.prototype.rejectPosition = function(){ this.offsetMap.pop() } /** * Get current layer of position from last offset of map * @returns {Number} */ Hemex.prototype.getLastPosition = function(){ return this.offsetMap.length == 0 ? this.offset : this.offsetMap.slice(-1)[0] } /** * Set last position offset from offset map last layer * @param {Number} n */ Hemex.prototype.setLastPosition = function(n){ if(this.offsetMap.length == 0) this.offset = n else this.offsetMap[this.offsetMap.length - 1] = n } /** * Get current layer of position from last offset of map * Some as getLastPosition() * @returns {Number} */ Hemex.prototype.getOffset = function(){ return this.getLastPosition() } /** * Set last position offset from offset map last layer and return it value * @param {Number} n * @returns {Number} */ Hemex.prototype.setOffset = function(n){ this.setLastPosition(n); return this.getLastPosition() } /** * Get text length * @type {Number} */ Hemex.prototype.length = 0; /** * Hemex lexing data * @type {String} */ Hemex.prototype.text = ""; /** * set lexing data * @param {String} text * @returns {void} */ Hemex.prototype.setText = function(text){ this.offset = 0; this.length = text.length; this.offsetMap = []; this.text = text; } /** * get lexing all data * @returns {String} */ Hemex.prototype.getText = function(){ return this.text; } /** * Get one character from cursor * @param {Number} n * @returns {String} */ Hemex.prototype.getChar = function(n){ return this.text.charAt(n?this.getOffset()+n:this.getOffset()) } /** * Boolean * @param {Number} n * @returns {String} */ Hemex.prototype.isChar = function(b){ return this.getChar() == b } /** * Dump all data from cursor position to end of char * @param {Number} n */ Hemex.prototype.dump = function(n){ return this.text.slice(this.getOffset(),this.getOffset()+n) } /** * Control coming end of line * @returns {Bollean} */ Hemex.prototype.isEnd = function(){ return this.length > this.getOffset() } /** * Forward one char */ Hemex.prototype.nextChar = function(){ this.setOffset(this.getOffset() + 1); } /** * Forward n char */ Hemex.prototype.toChar = function(n){ this.setOffset(this.getOffset() + n); } /** * Reading while end of line * @returns {String} */ Hemex.prototype.getLine = function(){ return this.of(function(){ switch(this.getChar()) { case Hemex.EOL: return false; default: return true; } }.bind(this)) } /** * Read all data until the function returns false * @param {Boolean} p * @param {(char:String)=>Boolean} e * @returns {String} */ Hemex.prototype.of = function(e,p){ let k = [],count=0; while(this.isEnd()){ if(e(p,count)) k.push(this.getChar()); else return k.join(''); count++; this.nextChar(); }; return k.length == 0 ? false : k.join('') } Hemex.prototype.each = function(e,p){ let k = []; while(this.isEnd()) if(!e(p)) return; else this.nextChar(); } Hemex.prototype.while = function(e,p){ let k = []; while(this.isEnd()) if(!e(p)) return; } /** * Controlling for current char type * @param {Boolean} reverse * @returns {Boolean} */ Hemex.prototype.isNumber = function(reverse){ let c = this.getChar().charCodeAt(0); let result = c >= 48 && c <= 57; return reverse ? !result : result; } /** * Read all data until char type is not number * @param {Boolean} reverse * @returns {String} */ Hemex.prototype.readNumbers = function(reverse){ return this.of(this.isNumber.bind(this),reverse) } /** * Controlling for current char type * @param {Boolean} reverse * @returns {Boolean} */ Hemex.prototype.isBigLetter = function(reverse){ let c = this.getChar().charCodeAt(0); let result = c >= 97 && c <= 122; return reverse ? !result : result; } /** * Controlling for current char type * @param {Boolean} reverse * @returns {Boolean} */ Hemex.prototype.isSmallLetter = function(reverse){ let c = this.getChar().charCodeAt(0); let result = c >= 65 && c <= 90; return reverse ? !result : result; } /** * Controlling for current char type * @param {Boolean} reverse * @returns {Boolean} */ Hemex.prototype.isLetter = function(reverse){ let result = this.isSmallLetter() || this.isBigLetter() return reverse ? !result : result; } /** * Controlling for current char type * @param {Boolean} reverse * @returns {Boolean} */ Hemex.prototype.isLetterRegex = function(reverse){ let result = /^[\p{L}]$/u.test(this.getChar()); return reverse ? !result : result; } /** * Read all data until char type is not letter * @param {Boolean} reverse * @returns {String} */ Hemex.prototype.readLetters = function(reverse){ return this.of(this.isLetter.bind(this),reverse) } /** * Controlling for current char type * @param {Boolean} reverse * @returns {Boolean} */ Hemex.prototype.isWhiteSpace = function(reverse){ let c = this.getChar(),ct = c.charCodeAt(0); let result = ( c == '\n' || c == '\r' || c == '\t' || c == ' ' || Hemex.WhiteSpace.includes(ct) ) return reverse ? !result : result; } /** * Read all data until char type is not white space * @param {Boolean} reverse * @returns {String} */ Hemex.prototype.readWhiteSpace = function(reverse){ return this.of(this.isWhiteSpace.bind(this),reverse) } /** * Controlling data * @param {Boolean} reverse * @returns {String} */ Hemex.prototype.include = function(words,next){ this.beginPosition(); for(let i = 0; i{ switch(c = this.getChar()) { case '0': case '1':{ data.push(c); break; } case '2': case '3': case '4': case '5': case '6': case '7':{ if(base >= 8){ data.push(c); break; }else return false; } case '8': case '9':{ if(base >= 10){ data.push(c); break; }else return false; } case 'A': case 'a': case 'B': case 'b': case 'C': case 'c': case 'D': case 'd': /* case 'E': case 'e': */ case 'F': case 'f':{ if(base >= 16){ data.push(c); break; }else return false; } case '.':{ if(!nextDot){ if(data.length == 0){ data.push("0"); }else data.push("."); nextDot = true; isFloat = true; }else{ throw new Error("Float number in Double dot"); }; break; } case 'E': case 'e':{ if(this.getChar(1)!='+'){ if(base == 16){ data.push(c); break; }else return false; }; if(data.length == 0){ this.rejectPosition(); return false; }; data.push('e'); this.nextChar(); if(this.getChar()=='+' || this.getChar()=='-'){ data.push(char()); this.nextChar(); }; let result = null; this.each(()=>{ switch(this.getChar()){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':{ data.push(this.getChar()); this.nextChar(); break; } default:{ return false; } } }) } default:{ return false; } }; return true }); return data.length == 0 ? false : [data.join(''),base] } Hemex.prototype.syntaxs = new Map(); /** * * @param {string} name * @param {(hmx:Hemex, result: (result:any) => any,...args:any[]) => any} callback */ Hemex.prototype.syntax = function(name, callback){ this.syntaxs.set(name, callback) } Hemex.prototype.give = function(name, ...args){ let sandbox = this.syntaxs.get(name); if(sandbox) { let res = undefined; this.beginPosition(); if(sandbox( this, arg => { res = arg }, ...args )) { this.acceptPosition(); return res; }else{ this.rejectPosition(); return res; } } } /** * @param {Error} message */ Hemex.prototype.throw = function(message){ throw new Error(message) };