lc2-compiler
Advanced tools
Comparing version 1.1.25 to 1.1.26
@@ -11,3 +11,3 @@ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.LCP = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
},{}],4:[function(require,module,exports){ | ||
'use strict';Object.defineProperty(exports,'__esModule',{value:!0});exports.Parser=exports.pluginTable=void 0;var _options=require('./options'),_locutil=require('./locutil'),_tokentype=require('./tokentype'),_identifier=require('./identifier'),_whitespace=require('./whitespace'),_ast=require('./ast'),_ast2=_interopRequireDefault(_ast),_macrosToOptions=require('./macros-to-options'),_macrosToOptions2=_interopRequireDefault(_macrosToOptions);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}const pluginTable=exports.pluginTable={};class Parser{constructor(a,b){this.options=a=(0,_options.getOptions)(a),this.keywords=_identifier.keywordRegexp,this.macros=_identifier.macroRegexp,this.input=b+'',this.loadPlugins(a.pluginList),this.sourceFile=a.sourceFile,this.pos=0,this.type=_tokentype.types.eof,this.value=null,this.start=this.end=this.pos,this.lastTokStart=this.lastTokEnd=this.pos,this.exprAllowed=!1,this.labels=[],this.conf={},this.globals=[],this.imports=[],this.nextID=0,this.pcs={},this.pcsTable={},this.inTag=!1}extend(a,b){this[a]=b(this[a])}loadPlugins(a){a.forEach(b=>{const c=pluginTable[b];if(!c)throw new Error('Plugin ['+b+'] not found');c(this,b)})}parse(){this.nextToken();let a={options:this.conf,processMap:this.pcs,global:this.globals,imports:null};return this.parseTopLevel(a)}raise(a,b){const c=(0,_locutil.getLineInfo)(this.input,a);b+=' ('+c.line+':'+c.column+')';const d=this.options.left,f=this.options.right,g=this.options.sourceFile?'An error occurs in: '+this.options.sourceFile+'\n':'';b=d||f?d+g+b+f:g+(0,_locutil.empowerErrMsg)(this.input,c,b);const h=this.pos;throw new _locutil.Lc2SyntaxError(b,a,c,h)}next(){this.lastTokEnd=this.end,this.lastTokStart=this.start,this.nextToken()}nextToken(){return this.skipSpace(),this.start=this.pos,this.pos>=this.input.length?this.finishToken(_tokentype.types.eof):void this.readToken(this.fullCharCodeAtPos())}readToken(a){return(0,_identifier.isIdentifierStart)(a)?this.readWord():this.getTokenFromCode(a)}fullCharCodeAtPos(){const a=this.input.charCodeAt(this.pos);if(55295>=a||57344<=a)return a;const b=this.input.charCodeAt(this.pos+1);return(a<<10)+b-56613888}skipBlockComment(){let a=this.pos,b=this.input.indexOf('*/',this.pos+=2);-1===b&&this.raise(this.pos-2,'unterminated comment'),this.pos=b+2,this.options.onComment&&this.options.onComment(!0,this.input.slice(a+2,b),a,this.pos)}skipLineComment(a){let b=this.pos,c=this.input.charCodeAt(this.pos+=a);for(;this.pos<this.input.length&&10!==c&&13!==c&&8232!==c&&8233!==c;)++this.pos,c=this.input.charCodeAt(this.pos);this.options.onComment&&this.options.onComment(!1,this.input.slice(b+=a,this.pos),b,this.pos)}skipSpace(){loop:for(;this.pos<this.input.length;){let a=this.input.charCodeAt(this.pos);switch(a){case 32:case 160:++this.pos;break;case 13:10===this.input.charCodeAt(this.pos+1)&&++this.pos;case 10:case 8232:case 8233:++this.pos;break;case 47:switch(this.input.charCodeAt(this.pos+1)){case 42:this.skipBlockComment();break;case 47:this.skipLineComment(2);break;default:break loop;}break;default:if(8<a&&14>a)++this.pos;else break loop;}}}readTokenSlash(){const a=this.input.charCodeAt(this.pos+1);return this.exprAllowed?(++this.pos,this.readRegexp()):61===a?this.finishOp(_tokentype.types.assign,2):62===a?this.finishOp(_tokentype.types.tagR,2):this.finishOp(_tokentype.types.slash,1)}readTokenMultModuloExp(a){const b=this.input.charCodeAt(this.pos+1),c=1,d=42===a?_tokentype.types.star:_tokentype.types.modulo;return 61===b?this.finishOp(_tokentype.types.assign,c+1):this.finishOp(d,c)}readTokenPipeAmp(a){const b=this.input.charCodeAt(this.pos+1);return b===a?this.finishOp(124===a?_tokentype.types.logicalOR:_tokentype.types.logicalAND,2):124===a?this.finishOp(_tokentype.types.pipe,1):void this.raise(this.pos,'bitwise operator is not allowed')}readTokenPlusMin(a){const b=this.input.charCodeAt(this.pos+1);return b===a?this.finishOp(_tokentype.types.incDec,2):61===b?this.finishOp(_tokentype.types.assign,2):this.finishOp(_tokentype.types.plusMin,1)}readTokenLt(){const a=this.input.charCodeAt(this.pos+1);return 35===a?this.finishOp(_tokentype.types.tagNumL,2):64===a?this.finishOp(_tokentype.types.tagAtL,2):33===a?this.finishOp(_tokentype.types.tagFacL,2):45===a?this.finishOp(_tokentype.types.tagMinues,2):124===a?this.finishOp(_tokentype.types.tagPipe,2):94===a?this.finishOp(_tokentype.types.tagXor,2):60===a?this.finishOp(_tokentype.types.tagShift,2):61===a?this.finishOp(_tokentype.types.relational,2):this.finishOp(_tokentype.types.relational,1)}readTokenGt(){const a=this.input.charCodeAt(this.pos+1);let b=1;return 62===a&&this.raise(this.pos,'bitwise operator is not allowed'),61===a&&(b=2),this.finishOp(_tokentype.types.relational,b)}readTokenEqExcl(a){const b=this.input.charCodeAt(this.pos+1);return 126===b&&33===a?this.finishOp(_tokentype.types.notMatch,2):61===b?this.finishOp(_tokentype.types.equality,61===this.input.charCodeAt(this.pos+2)?3:2):this.finishOp(61===a?_tokentype.types.eq:_tokentype.types.prefix,1)}getTokenFromCode(a){switch(a){case 35:return++this.pos,this.readMacro();case 40:return++this.pos,this.finishToken(_tokentype.types.parenL);case 41:return++this.pos,this.finishToken(_tokentype.types.parenR);case 59:return++this.pos,this.finishToken(_tokentype.types.semi);case 44:return++this.pos,this.finishToken(_tokentype.types.comma);case 91:return++this.pos,this.finishToken(_tokentype.types.bracketL);case 93:return++this.pos,this.finishToken(_tokentype.types.bracketR);case 123:return++this.pos,this.finishToken(_tokentype.types.braceL);case 125:return++this.pos,this.finishToken(_tokentype.types.braceR);case 58:return++this.pos,this.finishToken(_tokentype.types.colon);case 63:return++this.pos,this.finishToken(_tokentype.types.question);case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return this.readNumber(!1);case 34:case 39:return this.readString(a);case 47:return this.readTokenSlash();case 37:case 42:return this.readTokenMultModuloExp(a);case 124:case 38:return this.readTokenPipeAmp(a);case 43:case 45:return this.readTokenPlusMin(a);case 60:return this.readTokenLt(a);case 62:return this.readTokenGt(a);case 61:case 33:return this.readTokenEqExcl(a);case 126:return 126!==this.input.charCodeAt(this.pos+1)&&this.raise(this.pos,'only ~~ is allowed'),this.finishOp(_tokentype.types.match,2);default:this.raise(this.pos,'Unexpected character "'+this.input[this.pos]+'"');}}finishOp(a,b){const c=this.input.slice(this.pos,this.pos+=b);return this.finishToken(a,c)}finishToken(a,b){this.end=this.pos,this.type=a,this.value=b,this.exprAllowed=a.beforeExpr}readRegexp(){let a,b,c=this.pos;for(;;){this.pos>=this.input.length&&this.raise(c,'Unterminated regular expression');let h=this.input.charAt(this.pos);if(_whitespace.lineBreak.test(h)&&this.raise(c,'Unterminated regular expression'),a)a=!1;else{if('['===h)b=!0;else if(']'===h&&b)b=!1;else if('/'===h&&!b)break;a='\\'===h}++this.pos}const d=this.input.slice(c,this.pos);++this.pos;const f=this.readWord1();if(f){let h=/^[gim]*$/;h.test(f)||this.raise(c,'Invalid regular expression flag')}const g=this.tryCreateRegex(d,f,c);return this.finishToken(_tokentype.types.regexp,g)}tryCreateRegex(a,b,c){try{return new RegExp(a,b)}catch(d){this.raise(c,'Error when creating regular expression'+d.message)}}readInt(a,b=null){let c=this.pos,d=0;for(let f=0,g=null===b?Infinity:b;f<g;++f){let j,h=this.fullCharCodeAtPos();if(j=97<=h?h-97+10:65<=h?h-65+10:48<=h&&57>=h?h-48:Infinity,j>=a)break;++this.pos,d=d*a+j}return this.pos===c||null!==b&&this.pos-c!==b?null:d}readNumber(a){let b=this.pos,c=!1;a||null!==this.readInt(10)||this.raise(b,'Invalid Number');let d=this.fullCharCodeAtPos();46===d&&(++this.pos,this.readInt(10),c=!0,d=this.fullCharCodeAtPos()),(69===d||101===d)&&(d=this.input.charCodeAt(++this.pos),(43===d||45===d)&&++this.pos,null===this.readInt(10)&&this.raise(b,'Invalid number'),c=!0),(0,_identifier.isIdentifierStart)(this.fullCharCodeAtPos())&&this.raise(this.pos,'Identifier directly after number');let g,f=this.input.slice(b,this.pos);return g=c?parseFloat(f):parseInt(f,10),this.finishToken(_tokentype.types.num,g)}readString(a){let b='',c=this.start,d=++this.pos;for(;;){this.pos>=this.input.length&&this.raise(c,'Unterminated string');let f=this.fullCharCodeAtPos();if(f===a)break;92===f?(b+=this.input.slice(d,this.pos),b+=this.readEscapedChar(),d=this.pos):((0,_whitespace.isNewLine)(f)&&this.raise(c,'Unterminated string'),++this.pos)}return b+=this.input.slice(d,this.pos++),this.finishToken(_tokentype.types.string,b)}readEscapedChar(){const a=this.input.charCodeAt(++this.pos);switch(++this.pos,a){case 110:return'\n';case 114:return'\r';case 116:return'\t';case 98:return'\b';case 118:return'\x0B';case 102:return'\f';case 13:10===this.fullCharCodeAtPos()&&++this.pos;case 10:return'';default:return'\\'+String.fromCharCode(a);}}readWord1(){let a='',b=this.pos;for(;this.pos<this.input.length;){let c=this.fullCharCodeAtPos();if((0,_identifier.isIdentifierChar)(c))++this.pos;else break}return a+=this.input.slice(b,this.pos),a}readWord(){const a=this.readWord1(),b=this.keywords.test(a)?_tokentype.keywords[a]:_tokentype.types.name;return this.finishToken(b,a)}readMacro(){const a=this.pos,b=this.readWord1();this.macros.test(b)||this.raise(a,'invalid macros');const c=_tokentype.keywords[b],d=this.pos;for(let f=this.fullCharCodeAtPos();this.pos<this.input.length&&10!==f&&13!==f&&8232!==f&&8233!==f;)++this.pos,f=this.input.charCodeAt(this.pos);const g=this.input.slice(d,this.pos).trim();return this.finishToken(c,g)}parseTopLevel(a){let b=this.pcsTable;for(b.main={pos:0};this.type!==_tokentype.types.eof;)this.parseStructure();const c=[].concat(_identifier.buildIn).concat(this.options.extraBuildIn);if(this.options.callCheck)for(let d in b)b[d]&&-1===c.indexOf(d)&&this.raise(b[d].pos,'Invalid call at');return this.options.sourceFile&&(a.imports=this.imports),a}parseStructure(){const a=this.type;if(a.macro)return this.parseSet();if(a===_tokentype.types._process)return this.parseProcess();if(a===_tokentype.types.name){const b=this.parseExprStatement(!0);return this.globals.push(b)}if(a===_tokentype.types._import){const b=this.parseImport();return this.imports.push(b)}this.raise(this.start,'Expect an import, macros or process')}parseSet(){const a=this.type;a.macro||this.unexpected();const b=_macrosToOptions2.default[a.label];b||this.raise(this.start,'Unexpected macro'),this.writeConfig(b),this.next()}writeConfig(a){let b;const c=this.conf;c[a]&&this.raise(this.start,this.type.keyword+' was defined already');let d,f,g=this.value.split(',');'screen'===a?(2!==g.length&&this.raise('Invalid arguments'),d=~~parseInt(g[0],10),f=~~parseInt(g[1],10),b={width:d,height:f}):'autoscroll'===a||'autocapture'===a||'autowait'===a?b=!0:b=parseInt(this.value,10);c[a]=b}parseProcess(){let a=this.startNode(),b=this.pcs,c=this.pcsTable;this.next();const d=this.parseIndent().BODY.IDENTIFIER;a.BODY.IDENTIFIER=d,b[d]&&this.raise(this.start,d+' process was defined already'),b[d]=a,c[d]=!1,this.parsePcParam(a),this.parsePcBlock(a),this.finishNodeAt(a,_ast2.default.PROCESS,this.pos)}parsePcParam(a){a.BODY.PARAMETER=this.eat(_tokentype.types.parenL)?this.parseBindingList(_tokentype.types.parenR,!1,!1):[]}parsePcBlock(a){const b=this.parseBlock();a.BODY.SEGMENT=b}parseBlock(){this.expect(_tokentype.types.braceL);const a=[];for(;!this.eat(_tokentype.types.braceR);){const b=this.parseStatement(!0);a.push(b)}return a}parseStatement(){let a=this.type,b=this.startNode();return a===_tokentype.types._click||a===_tokentype.types._rclick||a===_tokentype.types._dblclick||a===_tokentype.types._movein||a===_tokentype.types._moveout?this.parseMouseAction(b,a.keyword):a===_tokentype.types._scroll?this.parseScrollAction(b,a.keyword):a===_tokentype.types._input||a===_tokentype.types._select?this.parseInputAction(b,a.keyword):a===_tokentype.types._check||a===_tokentype.types._uncheck?this.parseCheck(b,a.keyword):a===_tokentype.types._return?this.parseReturnStatement(b):a===_tokentype.types._wait?this.parseWaitStatement(b):a===_tokentype.types._assert||a===_tokentype.types._verify?this.parseAssertStatement(b,a.keyword):a===_tokentype.types._log||a===_tokentype.types._console?this.parseLogStatement(b):a===_tokentype.types._jumpto?this.parseGotoStatement(b):a===_tokentype.types._refresh?this.parseRefreshStatement(b):a===_tokentype.types.name?this.parseExprStatement(!1):a===_tokentype.types._if?this.parseIfStatement(b):a===_tokentype.types._while?this.parseWhileStatement(b):a===_tokentype.types.braceL?this.parseBlock():this.parseEvaluation(b)}parseReturnStatement(a){if(this.next(),this.eat(_tokentype.types.semi)){const b=this.startNode();b.BODY.DESTINATION=1,this.finishNode(b,'LITERAL'),a.BODY.RET=b}else a.BODY.RET=this.parseExpression(),this.semicolon();return this.finishNode(a,_ast2.default.RETURN)}parseExprStatement(a){const b=this.parseExpression();if(this.semicolon(),b.BODY.SYMBOL===_ast2.default.CALL){const c=b.BODY.IDENTIFIER;!1!==this.pcsTable[c]&&(this.pcsTable[c]={pos:this.lastTokStart}),a&&this.raise(b.POSITION.start,'invalid globals')}return b}parseEvaluation(){const a=this.parseExpression();return this.semicolon(),a}parseWaitStatement(a){return this.next(),a.BODY.DELAY=this.parseExpression(),this.semicolon(),this.finishNode(a,_ast2.default.WAIT)}parseMouseAction(a,b){if(this.next(),a.BODY.SELECTOR=this.parseExpression(),a.BODY.ACTION=b,this.eat(_tokentype.types._to)){let c,d;c=this.parseMaybeAssign(),this.expect(_tokentype.types.comma),d=this.parseMaybeAssign(),a.BODY.posX=c,a.BODY.posY=d}return this.semicolon(),this.finishNode(a,_ast2.default[b])}parseScrollAction(a,b){return this.next(),a.BODY.SELECTOR=this.parseExpression(),this.expect(_tokentype.types._by),a.BODY.PARAMS=this.parseExpression(),a.BODY.ACTION=b,this.finishNode(a,_ast2.default[b])}parseInputAction(a,b){return this.next(),a.BODY.SELECTOR=this.parseExpression(),this.expect(_tokentype.types._by),a.BODY.VALUE=this.parseExpression(),a.BODY.ACTION=b,this.semicolon(),this.finishNode(a,_ast2.default[b])}parseCheck(a,b){return this.next(),a.BODY.SELECTOR=this.parseExpression(),a.BODY.ACTION=b,this.semicolon(),this.finishNode(a,_ast2.default[b])}parseAssertStatement(a,b){return this.next(),a.BODY.TEST=this.parseExpression(),this.eat(_tokentype.types._in)&&(a.BODY.LIMIT=this.parseExpression()),this.semicolon(),a.BODY.key=this.getUID('#'),this.finishNode(a,_ast2.default[b])}parseGotoStatement(a){return this.next(),a.BODY.URL=this.parseExpression(),this.semicolon(),this.finishNode(a,_ast2.default.JUMPTO)}parseRefreshStatement(a){return this.next(),this.semicolon(),this.finishNode(a,_ast2.default.REFRESH)}parseLogStatement(a){return this.next(),a.BODY.LOG=this.parseExpression(),this.semicolon(),this.finishNode(a,_ast2.default.LOG)}parseIfStatement(a){return this.next(),a.BODY.CONDITION=this.parseParenExpression(),a.BODY.SEGMENT_TRUE=this.parseBlock(),a.BODY.SEGMENT_FALSE=this.eat(_tokentype.types._else)?[].concat(this.parseStatement()):[],this.finishNode(a,_ast2.default.BRANCH)}parseWhileStatement(a){return this.next(),a.BODY.CONDITION=this.parseParenExpression(),a.BODY.SEGMENT=this.parseStatement(),this.finishNode(a,_ast2.default.LOOP)}parseImport(){this.next(),this.type!==_tokentype.types.string&&this.raise(this.start,'invalid import path');const a=this.parseExprAtom().BODY.DESTINATION;return this.semicolon(),a}startNode(){return{POSITION:{LINE:(0,_locutil.getLineInfo)(this.input,this.start).line,start:this.start,end:0,source:this.sourceFile},BODY:{SYMBOL:''}}}startNodeAt(a){return{POSITION:{LINE:(0,_locutil.getLineInfo)(this.input,this.start).line,start:a,end:0,source:this.sourceFile},BODY:{SYMBOL:''}}}finishNode(a,b){return a.BODY.SYMBOL=b,a.POSITION.end=this.lastTokEnd,a}finishNodeAt(a,b,c){return a.BODY.SYMBOL=b,a.POSITION.end=c,a}eat(a){return this.type===a&&(this.next(),!0)}semicolon(){this.eat(_tokentype.types.semi)||this.expected(_tokentype.types.semi)}expect(a){return this.eat(a)||this.expected(a)}unexpected(a=this.start){this.raise(a,'Unexpected token')}expected(a){this.raise(this.lastTokEnd,'Expect a "'+a.label+'" after')}getUID(a){return a+this.nextID++}parseExpression(){const a=this.parseMaybeAssign();return a}parseMaybeAssign(){const a=this.start,b=this.parseMaybeConditional();if(this.type.isAssign){const c=this.startNodeAt(a),d='ES'+this.value;return c.BODY.IDENTIFIER=b.BODY.IDENTIFIER,this.next(),c.BODY.SOURCES=this.parseMaybeAssign(),this.finishNode(c,d)}return b}parseMaybeConditional(){let a=this.pos,b=this.parseExprOps();if(this.eat(_tokentype.types.question)){const c=this.startNodeAt(a);return c.BODY.CONDITION=b,c.BODY.TRUE=this.parseMaybeAssign(),this.expect(_tokentype.types.colon),c.BODY.FALSE=this.parseMaybeAssign(),this.finishNode(c,'ES?:')}return b}parseExprOps(){const a=this.start,b=this.parseMaybeUnary(!1);return this.parseExprOp(b,a,-1)}parseExprOp(a,b,c){const d=this.type.binop;if(null!==d&&d>c){const f=this.type,g=this.value;this.next();const h=this.start,j=this.parseExprOp(this.parseMaybeUnary(!1),h,d),k=this.buildBinary(b,a,j,g,f);return this.parseExprOp(k,b,c)}return a}buildBinary(a,b,c,d,f){const g=this.startNodeAt(a);g.BODY.LEFT=b,g.BODY.RIGHT=c;let h;return h=f===_tokentype.types.logicalAND||f===_tokentype.types.logicalOR?'ES'+f.label:f===_tokentype.types.notMatch||f===_tokentype.types.match?'LC'+f.label:f.isTag?'LC'+f.label:'ES'+d,this.finishNode(g,h)}parseMaybeUnary(){let a;const b=this.start;if(this.type.prefix){const c=this.startNode(),d='ES'+this.value;c.BODY.prefix=!0,this.next(),c.BODY.SOURCES=this.parseMaybeUnary(!1),a=this.finishNode(c,d)}else for(a=this.parseExprSubscripts();this.type.postfix;){let c=this.startNodeAt(b);const d='ES'+this.value;c.BODY.prefix=!1,c.BODY.DESTINATION=a,this.next(),a=this.finishNode(c,d)}return a}parseExprSubscripts(){const a=this.start,b=this.parseExprAtom();return this.parseSubscripts(b,a)}parseSubscripts(a,b){if(this.eat(_tokentype.types.parenL)){const c=this.startNodeAt(b),d=this.parseExprList(_tokentype.types.parenR,!1,!1);return c.BODY.IDENTIFIER=a.BODY.IDENTIFIER,c.BODY.ARGUMENTS=d,this.finishNode(c,_ast2.default.CALL)}return a}parseExprAtom(){const a=this.type;return a===_tokentype.types.name?this.parseIndent(a!==_tokentype.types.name):a===_tokentype.types.regexp||a===_tokentype.types.num||a===_tokentype.types.string?this.parseLiteral(_ast2.default.LITERAL,this.value):a===_tokentype.types._true||a===_tokentype.types._false?this.parseLiteral(_ast2.default.LITERAL,a===_tokentype.types._true):a===_tokentype.types.parenL?this.parseParenExpression():a===_tokentype.types.tagAtL||a===_tokentype.types.tagNumL||a===_tokentype.types.tagFacL||a===_tokentype.types.tagMinues||a===_tokentype.types.tagPipe||a===_tokentype.types.tagXor||a===_tokentype.types.tagShift?this.parseTagExpression():this.inTag?this.raise(this.lastTokStart,'(missing `/` before `>` ?) Unexpected token'):this.unexpected()}parseLiteral(a,b){const c=this.startNode();return c.BODY.DESTINATION=b,c.BODY.raw=this.input.slice(this.start,this.end),this.next(),this.finishNode(c,_ast2.default.LITERAL)}parseParenExpression(){this.expect(_tokentype.types.parenL);const a=this.parseExpression();return this.expect(_tokentype.types.parenR),a}parseTagExpression(){const a='LC'+this.type.label,b=this.startNode();return this.inTag=!0,this.next(),b.BODY.SELECTOR=this.parseExpression(),this.expect(_tokentype.types.tagR),this.inTag=!1,this.finishNode(b,a)}parseExprList(a,b){const c=[];for(let d=!0;!this.eat(a);)if(d?d=!1:this.expect(_tokentype.types.comma),b&&this.type===_tokentype.types.comma)c.push(null);else{const f=this.parseMaybeAssign();c.push(f)}return c}parseIndent(){const a=this.startNode();return this.type===_tokentype.types.name?a.BODY.IDENTIFIER=this.value:this.unexpected(),this.next(),this.finishNode(a,_ast2.default.VARIABLE)}parseBindingList(a,b,c){const d=[];for(let f=!0;!this.eat(a);)if(f?f=!1:this.expect(_tokentype.types.comma),b&&this.type===_tokentype.types.comma)d.push(null);else if(c)break;else{const g=this.parseIndent();d.push(g.BODY.IDENTIFIER)}return d}}exports.Parser=Parser; | ||
'use strict';Object.defineProperty(exports,'__esModule',{value:!0});exports.Parser=exports.pluginTable=void 0;var _options=require('./options'),_locutil=require('./locutil'),_tokentype=require('./tokentype'),_identifier=require('./identifier'),_whitespace=require('./whitespace'),_ast=require('./ast'),_ast2=_interopRequireDefault(_ast),_macrosToOptions=require('./macros-to-options'),_macrosToOptions2=_interopRequireDefault(_macrosToOptions);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}const pluginTable=exports.pluginTable={};class Parser{constructor(a,b){this.options=a=(0,_options.getOptions)(a),this.keywords=_identifier.keywordRegexp,this.macros=_identifier.macroRegexp,this.input=b+'',this.loadPlugins(a.pluginList),this.sourceFile=a.sourceFile,this.pos=0,this.type=_tokentype.types.eof,this.value=null,this.start=this.end=this.pos,this.lastTokStart=this.lastTokEnd=this.pos,this.exprAllowed=!1,this.labels=[],this.conf={},this.globals=[],this.imports=[],this.nextID=0,this.pcs={},this.pcsTable={},this.inTag=!1}extend(a,b){this[a]=b(this[a])}loadPlugins(a){a.forEach(b=>{const c=pluginTable[b];if(!c)throw new Error('Plugin ['+b+'] not found');c(this,b)})}parse(){this.nextToken();let a={options:this.conf,processMap:this.pcs,global:this.globals,imports:null};return this.parseTopLevel(a)}raise(a,b){const c=(0,_locutil.getLineInfo)(this.input,a);b+=' ('+c.line+':'+c.column+')';const d=this.options.left,f=this.options.right,g=this.options.sourceFile?'An error occurs in: '+this.options.sourceFile+'\n':'';b=d||f?d+g+b+f:g+(0,_locutil.empowerErrMsg)(this.input,c,b);const h=this.pos;throw new _locutil.Lc2SyntaxError(b,a,c,h)}next(){this.lastTokEnd=this.end,this.lastTokStart=this.start,this.nextToken()}nextToken(){return this.skipSpace(),this.start=this.pos,this.pos>=this.input.length?this.finishToken(_tokentype.types.eof):void this.readToken(this.fullCharCodeAtPos())}readToken(a){return(0,_identifier.isIdentifierStart)(a)?this.readWord():this.getTokenFromCode(a)}fullCharCodeAtPos(){const a=this.input.charCodeAt(this.pos);if(55295>=a||57344<=a)return a;const b=this.input.charCodeAt(this.pos+1);return(a<<10)+b-56613888}skipBlockComment(){let a=this.pos,b=this.input.indexOf('*/',this.pos+=2);-1===b&&this.raise(this.pos-2,'unterminated comment'),this.pos=b+2,this.options.onComment&&this.options.onComment(!0,this.input.slice(a+2,b),a,this.pos)}skipLineComment(a){let b=this.pos,c=this.input.charCodeAt(this.pos+=a);for(;this.pos<this.input.length&&10!==c&&13!==c&&8232!==c&&8233!==c;)++this.pos,c=this.input.charCodeAt(this.pos);this.options.onComment&&this.options.onComment(!1,this.input.slice(b+=a,this.pos),b,this.pos)}skipSpace(){loop:for(;this.pos<this.input.length;){let a=this.input.charCodeAt(this.pos);switch(a){case 32:case 160:++this.pos;break;case 13:10===this.input.charCodeAt(this.pos+1)&&++this.pos;case 10:case 8232:case 8233:++this.pos;break;case 47:switch(this.input.charCodeAt(this.pos+1)){case 42:this.skipBlockComment();break;case 47:this.skipLineComment(2);break;default:break loop;}break;default:if(8<a&&14>a)++this.pos;else break loop;}}}readTokenSlash(){const a=this.input.charCodeAt(this.pos+1);return this.exprAllowed?(++this.pos,this.readRegexp()):61===a?this.finishOp(_tokentype.types.assign,2):62===a?this.finishOp(_tokentype.types.tagR,2):this.finishOp(_tokentype.types.slash,1)}readTokenMultModuloExp(a){const b=this.input.charCodeAt(this.pos+1),c=1,d=42===a?_tokentype.types.star:_tokentype.types.modulo;return 61===b?this.finishOp(_tokentype.types.assign,c+1):this.finishOp(d,c)}readTokenPipeAmp(a){const b=this.input.charCodeAt(this.pos+1);return b===a?this.finishOp(124===a?_tokentype.types.logicalOR:_tokentype.types.logicalAND,2):124===a?this.finishOp(_tokentype.types.pipe,1):void this.raise(this.pos,'bitwise operator is not allowed')}readTokenPlusMin(a){const b=this.input.charCodeAt(this.pos+1);return b===a?this.finishOp(_tokentype.types.incDec,2):61===b?this.finishOp(_tokentype.types.assign,2):this.finishOp(_tokentype.types.plusMin,1)}readTokenLt(){const a=this.input.charCodeAt(this.pos+1);return 35===a?this.finishOp(_tokentype.types.tagNumL,2):64===a?this.finishOp(_tokentype.types.tagAtL,2):33===a?this.finishOp(_tokentype.types.tagFacL,2):45===a?this.finishOp(_tokentype.types.tagMinues,2):124===a?this.finishOp(_tokentype.types.tagPipe,2):94===a?this.finishOp(_tokentype.types.tagXor,2):60===a?this.finishOp(_tokentype.types.tagShift,2):61===a?this.finishOp(_tokentype.types.relational,2):this.finishOp(_tokentype.types.relational,1)}readTokenGt(){const a=this.input.charCodeAt(this.pos+1);let b=1;return 62===a&&this.raise(this.pos,'bitwise operator is not allowed'),61===a&&(b=2),this.finishOp(_tokentype.types.relational,b)}readTokenEqExcl(a){const b=this.input.charCodeAt(this.pos+1);return 126===b&&33===a?this.finishOp(_tokentype.types.notMatch,2):61===b?this.finishOp(_tokentype.types.equality,61===this.input.charCodeAt(this.pos+2)?3:2):this.finishOp(61===a?_tokentype.types.eq:_tokentype.types.prefix,1)}getTokenFromCode(a){switch(a){case 35:return++this.pos,this.readMacro();case 40:return++this.pos,this.finishToken(_tokentype.types.parenL);case 41:return++this.pos,this.finishToken(_tokentype.types.parenR);case 59:return++this.pos,this.finishToken(_tokentype.types.semi);case 44:return++this.pos,this.finishToken(_tokentype.types.comma);case 91:return++this.pos,this.finishToken(_tokentype.types.bracketL);case 93:return++this.pos,this.finishToken(_tokentype.types.bracketR);case 123:return++this.pos,this.finishToken(_tokentype.types.braceL);case 125:return++this.pos,this.finishToken(_tokentype.types.braceR);case 58:return++this.pos,this.finishToken(_tokentype.types.colon);case 63:return++this.pos,this.finishToken(_tokentype.types.question);case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return this.readNumber(!1);case 34:case 39:return this.readString(a);case 47:return this.readTokenSlash();case 37:case 42:return this.readTokenMultModuloExp(a);case 124:case 38:return this.readTokenPipeAmp(a);case 43:case 45:return this.readTokenPlusMin(a);case 60:return this.readTokenLt(a);case 62:return this.readTokenGt(a);case 61:case 33:return this.readTokenEqExcl(a);case 126:return 126!==this.input.charCodeAt(this.pos+1)&&this.raise(this.pos,'only ~~ is allowed'),this.finishOp(_tokentype.types.match,2);default:this.raise(this.pos,'Unexpected character "'+this.input[this.pos]+'"');}}finishOp(a,b){const c=this.input.slice(this.pos,this.pos+=b);return this.finishToken(a,c)}finishToken(a,b){this.end=this.pos,this.type=a,this.value=b,this.exprAllowed=a.beforeExpr}readRegexp(){let a,b,c=this.pos;for(;;){this.pos>=this.input.length&&this.raise(c,'Unterminated regular expression');let h=this.input.charAt(this.pos);if(_whitespace.lineBreak.test(h)&&this.raise(c,'Unterminated regular expression'),a)a=!1;else{if('['===h)b=!0;else if(']'===h&&b)b=!1;else if('/'===h&&!b)break;a='\\'===h}++this.pos}const d=this.input.slice(c,this.pos);++this.pos;const f=this.readWord1();if(f){let h=/^[gim]*$/;h.test(f)||this.raise(c,'Invalid regular expression flag')}const g=this.tryCreateRegex(d,f,c);return this.finishToken(_tokentype.types.regexp,g)}tryCreateRegex(a,b,c){try{return new RegExp(a,b)}catch(d){this.raise(c,'Error when creating regular expression'+d.message)}}readInt(a,b=null){let c=this.pos,d=0;for(let f=0,g=null===b?Infinity:b;f<g;++f){let j,h=this.fullCharCodeAtPos();if(j=97<=h?h-97+10:65<=h?h-65+10:48<=h&&57>=h?h-48:Infinity,j>=a)break;++this.pos,d=d*a+j}return this.pos===c||null!==b&&this.pos-c!==b?null:d}readNumber(a){let b=this.pos,c=!1;a||null!==this.readInt(10)||this.raise(b,'Invalid Number');let d=this.fullCharCodeAtPos();46===d&&(++this.pos,this.readInt(10),c=!0,d=this.fullCharCodeAtPos()),(69===d||101===d)&&(d=this.input.charCodeAt(++this.pos),(43===d||45===d)&&++this.pos,null===this.readInt(10)&&this.raise(b,'Invalid number'),c=!0),(0,_identifier.isIdentifierStart)(this.fullCharCodeAtPos())&&this.raise(this.pos,'Identifier directly after number');let g,f=this.input.slice(b,this.pos);return g=c?parseFloat(f):parseInt(f,10),this.finishToken(_tokentype.types.num,g)}readString(a){let b='',c=this.start,d=++this.pos;for(;;){this.pos>=this.input.length&&this.raise(c,'Unterminated string');let f=this.fullCharCodeAtPos();if(f===a)break;92===f?(b+=this.input.slice(d,this.pos),b+=this.readEscapedChar(),d=this.pos):((0,_whitespace.isNewLine)(f)&&this.raise(c,'Unterminated string'),++this.pos)}return b+=this.input.slice(d,this.pos++),this.finishToken(_tokentype.types.string,b)}readEscapedChar(){const a=this.input.charCodeAt(++this.pos);switch(++this.pos,a){case 110:return'\n';case 114:return'\r';case 116:return'\t';case 98:return'\b';case 118:return'\x0B';case 102:return'\f';case 13:10===this.fullCharCodeAtPos()&&++this.pos;case 10:return'';default:return'\\'+String.fromCharCode(a);}}readWord1(){let a='',b=this.pos;for(;this.pos<this.input.length;){let c=this.fullCharCodeAtPos();if((0,_identifier.isIdentifierChar)(c))++this.pos;else break}return a+=this.input.slice(b,this.pos),a}readWord(){const a=this.readWord1(),b=this.keywords.test(a)?_tokentype.keywords[a]:_tokentype.types.name;return this.finishToken(b,a)}readMacro(){const a=this.pos,b=this.readWord1();this.macros.test(b)||this.raise(a,'invalid macros');const c=_tokentype.keywords[b],d=this.pos;for(let f=this.fullCharCodeAtPos();this.pos<this.input.length&&10!==f&&13!==f&&8232!==f&&8233!==f;)++this.pos,f=this.input.charCodeAt(this.pos);const g=this.input.slice(d,this.pos).trim();return this.finishToken(c,g)}parseTopLevel(a){let b=this.pcsTable;for(b.main={pos:0};this.type!==_tokentype.types.eof;)this.parseStructure();const c=[].concat(_identifier.buildIn).concat(this.options.extraBuildIn);if(this.options.callCheck)for(let d in b)b[d]&&-1===c.indexOf(d)&&this.raise(b[d].pos,'Invalid call at');return this.options.sourceFile&&(a.imports=this.imports),a}parseStructure(){const a=this.type;if(a.macro)return this.parseSet();if(a===_tokentype.types._process)return this.parseProcess();if(a===_tokentype.types.name){const b=this.parseExprStatement(!0);return this.globals.push(b)}if(a===_tokentype.types._import){const b=this.parseImport();return this.imports.push(b)}this.raise(this.start,'Expect an import, macros or process')}parseSet(){const a=this.type;a.macro||this.unexpected();const b=_macrosToOptions2.default[a.label];b||this.raise(this.start,'Unexpected macro'),this.writeConfig(b),this.next()}writeConfig(a){let b;const c=this.conf;c[a]&&this.raise(this.start,this.type.keyword+' was defined already');let d,f,g=this.value.split(',');switch(a){case _macrosToOptions2.default.SCREEN:2!==g.length&&this.raise('Invalid arguments'),d=~~parseInt(g[0],10),f=~~parseInt(g[1],10),b={width:d,height:f};break;case _macrosToOptions2.default.AUTOWAIT:if(this.value){c[a]=parseInt(this.value,10);break}else return;default:b=parseInt(this.value,10);}c[a]=b}parseProcess(){let a=this.startNode(),b=this.pcs,c=this.pcsTable;this.next();const d=this.parseIndent().BODY.IDENTIFIER;a.BODY.IDENTIFIER=d,b[d]&&this.raise(this.start,d+' process was defined already'),b[d]=a,c[d]=!1,this.parsePcParam(a),this.parsePcBlock(a),this.finishNodeAt(a,_ast2.default.PROCESS,this.pos)}parsePcParam(a){a.BODY.PARAMETER=this.eat(_tokentype.types.parenL)?this.parseBindingList(_tokentype.types.parenR,!1,!1):[]}parsePcBlock(a){const b=this.parseBlock();a.BODY.SEGMENT=b}parseBlock(){this.expect(_tokentype.types.braceL);const a=[];for(;!this.eat(_tokentype.types.braceR);){const b=this.parseStatement(!0);a.push(b)}return a}parseStatement(){let a=this.type,b=this.startNode();return a===_tokentype.types._click||a===_tokentype.types._rclick||a===_tokentype.types._dblclick||a===_tokentype.types._movein||a===_tokentype.types._moveout?this.parseMouseAction(b,a.keyword):a===_tokentype.types._scroll?this.parseScrollAction(b,a.keyword):a===_tokentype.types._input||a===_tokentype.types._select?this.parseInputAction(b,a.keyword):a===_tokentype.types._check||a===_tokentype.types._uncheck?this.parseCheck(b,a.keyword):a===_tokentype.types._return?this.parseReturnStatement(b):a===_tokentype.types._wait?this.parseWaitStatement(b):a===_tokentype.types._assert||a===_tokentype.types._verify?this.parseAssertStatement(b,a.keyword):a===_tokentype.types._log||a===_tokentype.types._console?this.parseLogStatement(b):a===_tokentype.types._jumpto?this.parseGotoStatement(b):a===_tokentype.types._refresh?this.parseRefreshStatement(b):a===_tokentype.types.name?this.parseExprStatement(!1):a===_tokentype.types._if?this.parseIfStatement(b):a===_tokentype.types._while?this.parseWhileStatement(b):a===_tokentype.types.braceL?this.parseBlock():this.parseEvaluation(b)}parseReturnStatement(a){if(this.next(),this.eat(_tokentype.types.semi)){const b=this.startNode();b.BODY.DESTINATION=1,this.finishNode(b,'LITERAL'),a.BODY.RET=b}else a.BODY.RET=this.parseExpression(),this.semicolon();return this.finishNode(a,_ast2.default.RETURN)}parseExprStatement(a){const b=this.parseExpression();if(this.semicolon(),b.BODY.SYMBOL===_ast2.default.CALL){const c=b.BODY.IDENTIFIER;!1!==this.pcsTable[c]&&(this.pcsTable[c]={pos:this.lastTokStart}),a&&this.raise(b.POSITION.start,'invalid globals')}return b}parseEvaluation(){const a=this.parseExpression();return this.semicolon(),a}parseWaitStatement(a){return this.next(),a.BODY.DELAY=this.parseExpression(),this.semicolon(),this.finishNode(a,_ast2.default.WAIT)}parseMouseAction(a,b){if(this.next(),a.BODY.SELECTOR=this.parseExpression(),a.BODY.ACTION=b,this.eat(_tokentype.types._to)){let c,d;c=this.parseMaybeAssign(),this.expect(_tokentype.types.comma),d=this.parseMaybeAssign(),a.BODY.posX=c,a.BODY.posY=d}return this.semicolon(),this.finishNode(a,_ast2.default[b])}parseScrollAction(a,b){return this.next(),a.BODY.SELECTOR=this.parseExpression(),this.expect(_tokentype.types._by),a.BODY.PARAMS=this.parseExpression(),a.BODY.ACTION=b,this.finishNode(a,_ast2.default[b])}parseInputAction(a,b){return this.next(),a.BODY.SELECTOR=this.parseExpression(),this.expect(_tokentype.types._by),a.BODY.VALUE=this.parseExpression(),a.BODY.ACTION=b,this.semicolon(),this.finishNode(a,_ast2.default[b])}parseCheck(a,b){return this.next(),a.BODY.SELECTOR=this.parseExpression(),a.BODY.ACTION=b,this.semicolon(),this.finishNode(a,_ast2.default[b])}parseAssertStatement(a,b){return this.next(),a.BODY.TEST=this.parseExpression(),this.eat(_tokentype.types._in)&&(a.BODY.LIMIT=this.parseExpression()),this.semicolon(),a.BODY.key=this.getUID('#'),this.finishNode(a,_ast2.default[b])}parseGotoStatement(a){return this.next(),a.BODY.URL=this.parseExpression(),this.semicolon(),this.finishNode(a,_ast2.default.JUMPTO)}parseRefreshStatement(a){return this.next(),this.semicolon(),this.finishNode(a,_ast2.default.REFRESH)}parseLogStatement(a){return this.next(),a.BODY.LOG=this.parseExpression(),this.semicolon(),this.finishNode(a,_ast2.default.LOG)}parseIfStatement(a){return this.next(),a.BODY.CONDITION=this.parseParenExpression(),a.BODY.SEGMENT_TRUE=this.parseBlock(),a.BODY.SEGMENT_FALSE=this.eat(_tokentype.types._else)?[].concat(this.parseStatement()):[],this.finishNode(a,_ast2.default.BRANCH)}parseWhileStatement(a){return this.next(),a.BODY.CONDITION=this.parseParenExpression(),a.BODY.SEGMENT=this.parseStatement(),this.finishNode(a,_ast2.default.LOOP)}parseImport(){this.next(),this.type!==_tokentype.types.string&&this.raise(this.start,'invalid import path');const a=this.parseExprAtom().BODY.DESTINATION;return this.semicolon(),a}startNode(){return{POSITION:{LINE:(0,_locutil.getLineInfo)(this.input,this.start).line,start:this.start,end:0,source:this.sourceFile},BODY:{SYMBOL:''}}}startNodeAt(a){return{POSITION:{LINE:(0,_locutil.getLineInfo)(this.input,this.start).line,start:a,end:0,source:this.sourceFile},BODY:{SYMBOL:''}}}finishNode(a,b){return a.BODY.SYMBOL=b,a.POSITION.end=this.lastTokEnd,a}finishNodeAt(a,b,c){return a.BODY.SYMBOL=b,a.POSITION.end=c,a}eat(a){return this.type===a&&(this.next(),!0)}semicolon(){this.eat(_tokentype.types.semi)||this.expected(_tokentype.types.semi)}expect(a){return this.eat(a)||this.expected(a)}unexpected(a=this.start){this.raise(a,'Unexpected token')}expected(a){this.raise(this.lastTokEnd,'Expect a "'+a.label+'" after')}getUID(a){return a+this.nextID++}parseExpression(){const a=this.parseMaybeAssign();return a}parseMaybeAssign(){const a=this.start,b=this.parseMaybeConditional();if(this.type.isAssign){const c=this.startNodeAt(a),d='ES'+this.value;return c.BODY.IDENTIFIER=b.BODY.IDENTIFIER,this.next(),c.BODY.SOURCES=this.parseMaybeAssign(),this.finishNode(c,d)}return b}parseMaybeConditional(){let a=this.pos,b=this.parseExprOps();if(this.eat(_tokentype.types.question)){const c=this.startNodeAt(a);return c.BODY.CONDITION=b,c.BODY.TRUE=this.parseMaybeAssign(),this.expect(_tokentype.types.colon),c.BODY.FALSE=this.parseMaybeAssign(),this.finishNode(c,'ES?:')}return b}parseExprOps(){const a=this.start,b=this.parseMaybeUnary(!1);return this.parseExprOp(b,a,-1)}parseExprOp(a,b,c){const d=this.type.binop;if(null!==d&&d>c){const f=this.type,g=this.value;this.next();const h=this.start,j=this.parseExprOp(this.parseMaybeUnary(!1),h,d),k=this.buildBinary(b,a,j,g,f);return this.parseExprOp(k,b,c)}return a}buildBinary(a,b,c,d,f){const g=this.startNodeAt(a);g.BODY.LEFT=b,g.BODY.RIGHT=c;let h;return h=f===_tokentype.types.logicalAND||f===_tokentype.types.logicalOR?'ES'+f.label:f===_tokentype.types.notMatch||f===_tokentype.types.match?'LC'+f.label:f.isTag?'LC'+f.label:'ES'+d,this.finishNode(g,h)}parseMaybeUnary(){let a;const b=this.start;if(this.type.prefix){const c=this.startNode(),d='ES'+this.value;c.BODY.prefix=!0,this.next(),c.BODY.SOURCES=this.parseMaybeUnary(!1),a=this.finishNode(c,d)}else for(a=this.parseExprSubscripts();this.type.postfix;){let c=this.startNodeAt(b);const d='ES'+this.value;c.BODY.prefix=!1,c.BODY.DESTINATION=a,this.next(),a=this.finishNode(c,d)}return a}parseExprSubscripts(){const a=this.start,b=this.parseExprAtom();return this.parseSubscripts(b,a)}parseSubscripts(a,b){if(this.eat(_tokentype.types.parenL)){const c=this.startNodeAt(b),d=this.parseExprList(_tokentype.types.parenR,!1,!1);return c.BODY.IDENTIFIER=a.BODY.IDENTIFIER,c.BODY.ARGUMENTS=d,this.finishNode(c,_ast2.default.CALL)}return a}parseExprAtom(){const a=this.type;return a===_tokentype.types.name?this.parseIndent(a!==_tokentype.types.name):a===_tokentype.types.regexp||a===_tokentype.types.num||a===_tokentype.types.string?this.parseLiteral(_ast2.default.LITERAL,this.value):a===_tokentype.types._true||a===_tokentype.types._false?this.parseLiteral(_ast2.default.LITERAL,a===_tokentype.types._true):a===_tokentype.types.parenL?this.parseParenExpression():a===_tokentype.types.tagAtL||a===_tokentype.types.tagNumL||a===_tokentype.types.tagFacL||a===_tokentype.types.tagMinues||a===_tokentype.types.tagPipe||a===_tokentype.types.tagXor||a===_tokentype.types.tagShift?this.parseTagExpression():this.inTag?this.raise(this.lastTokStart,'(missing `/` before `>` ?) Unexpected token'):this.unexpected()}parseLiteral(a,b){const c=this.startNode();return c.BODY.DESTINATION=b,c.BODY.raw=this.input.slice(this.start,this.end),this.next(),this.finishNode(c,_ast2.default.LITERAL)}parseParenExpression(){this.expect(_tokentype.types.parenL);const a=this.parseExpression();return this.expect(_tokentype.types.parenR),a}parseTagExpression(){const a='LC'+this.type.label,b=this.startNode();return this.inTag=!0,this.next(),b.BODY.SELECTOR=this.parseExpression(),this.expect(_tokentype.types.tagR),this.inTag=!1,this.finishNode(b,a)}parseExprList(a,b){const c=[];for(let d=!0;!this.eat(a);)if(d?d=!1:this.expect(_tokentype.types.comma),b&&this.type===_tokentype.types.comma)c.push(null);else{const f=this.parseMaybeAssign();c.push(f)}return c}parseIndent(){const a=this.startNode();return this.type===_tokentype.types.name?a.BODY.IDENTIFIER=this.value:this.unexpected(),this.next(),this.finishNode(a,_ast2.default.VARIABLE)}parseBindingList(a,b,c){const d=[];for(let f=!0;!this.eat(a);)if(f?f=!1:this.expect(_tokentype.types.comma),b&&this.type===_tokentype.types.comma)d.push(null);else if(c)break;else{const g=this.parseIndent();d.push(g.BODY.IDENTIFIER)}return d}}exports.Parser=Parser; | ||
@@ -14,0 +14,0 @@ },{"./ast":2,"./identifier":3,"./locutil":5,"./macros-to-options":6,"./options":7,"./tokentype":8,"./whitespace":9}],5:[function(require,module,exports){ |
{ | ||
"name": "lc2-compiler", | ||
"version": "1.1.25", | ||
"version": "1.1.26", | ||
"description": "lemoncase2 parser", | ||
@@ -40,3 +40,3 @@ "main": "dist/bundle.js", | ||
"cross-env": "^3.1.3", | ||
"eslint-plugin-flowtype": "^2.25.0", | ||
"eslint-plugin-flowtype": "^2.29.1", | ||
"flow-bin": "^0.36.0", | ||
@@ -43,0 +43,0 @@ "mocha": "^3.2.0", |
@@ -8,3 +8,3 @@ const assert = require('assert'); | ||
module.exports = function (code, masterOption) { | ||
const parseFile = function (code, masterOption) { | ||
assert(masterOption, 'no source file found'); | ||
@@ -68,2 +68,3 @@ assert(masterOption.sourceFile, 'no source file found'); | ||
module.exports = parseFile; | ||
module.exports.matchImport = matchAllImport; | ||
@@ -88,1 +89,11 @@ | ||
} | ||
module.exports.from = function (filepath, options) { | ||
filepath = path.resolve(filepath); | ||
const masterCode = fs.readFileSync(filepath, 'utf8'); | ||
options = options || {}; | ||
options.sourceFile = filepath; | ||
return parseFile(masterCode, options); | ||
}; |
349
README.md
@@ -0,1 +1,350 @@ | ||
# Lemoncase2 | ||
用来描述测试用例的语言 | ||
# 语法 | ||
所有的语句必须以分号 ; 结尾 | ||
例: | ||
`click 'here';` | ||
## 变量 | ||
类似于 python : | ||
```Python | ||
a = 1; | ||
a = true; | ||
``` | ||
## 类型 | ||
**Lemoncase2 有以下数据类型** | ||
* 数值 (e.g., 0.12, 1e-3) | ||
* 字符 (e.g., 'you', "me") | ||
* 布尔 (true/false) | ||
* 正则 (/abs/i) | ||
## 宏指令 | ||
宏指令定义了测试用例运行的参数。 | ||
### #TIMES [times:number|1] | ||
```C | ||
// 用例会运行 10 次。 | ||
#TIMES 10 | ||
``` | ||
### #INTERVAL [interval:number|3000] | ||
```C | ||
// 用例执行的间隔是 1000 毫秒。 | ||
#INTERVAL 1000 | ||
``` | ||
### #SCREEN [width:number],[height:number] | ||
```C | ||
// 将待测页面的宽度设为 800px 高度设为 height 600px。 | ||
#SCREEN 800,600 | ||
``` | ||
### #AUTOWAIT | ||
```C | ||
// 自动等待 | ||
#AUTOSCROLL | ||
``` | ||
### #LIMIT [time:number] | ||
```C | ||
// 时间限制 | ||
#LIMIT 50 | ||
``` | ||
## 指令 | ||
### [action] [selector:string] by/to [params|params1,params2] | ||
模拟用户操作的指令。 | ||
### assert [exp][ in [overtime:number]] | ||
断言当前的表达式[时间限制]。 | ||
### wait [time:number] | ||
等待一定时间。 | ||
### log [exp] | ||
在控制台中输出表达式的结果。 | ||
### jumpto [exp] | ||
跳转到一个链接。 | ||
### refresh | ||
刷新当前页面。 | ||
### process [identifier] { [statements] } | ||
定义一个过程 / 函数。 | ||
## 动作指令关键字 | ||
### input | ||
输入文字到 input 元素 `<input type="text" />` 或 `<textarea>`. | ||
```C | ||
// <input id="link" class="case" /> | ||
input 'div#link.case' by "hello world."; | ||
``` | ||
### click | ||
鼠标左键单击一个元素. | ||
```C | ||
// <a href="...">Text</a> | ||
click 'a'; | ||
// <a id="link" href="...">Text</a> | ||
click 'a#link'; | ||
``` | ||
### dblclick | ||
鼠标双击一个元素. | ||
```C | ||
// <div id="link" class="case">Text</div> | ||
dblclick 'div#link.case'; | ||
``` | ||
### rclick | ||
鼠标右键单击一个元素. | ||
```C | ||
// <div id="link" class="case">Text</div> | ||
rclick 'div#link.case'; | ||
``` | ||
### select [selector:string] by [value:string|index:number] | ||
从选择列表下拉中选中 <option> 目标是 <select> 元素。参数可以是: value|index. | ||
*(仅能使用在 <select> 元素上)* | ||
```C | ||
// <select> | ||
// <option value="a"></option> // index:0 | ||
// <option value="b"></option> // index:1 <-- 这个会被选中 | ||
// <option value="c"></option> // index:2 | ||
// </select> | ||
select "select" by 1; | ||
// 或 | ||
select "select" by "b"; | ||
``` | ||
### movein - beta | ||
鼠标经过一个HTML元素. | ||
### moveout - beta | ||
鼠标移出一个HTML元素. | ||
### scroll - beta | ||
滚动到页面上的一个位置. | ||
目前版本不支持对 `<iframe>` 元素派发事件, 所以如果待测页面正在使用如 JEECG 等“企业级”应用时,很多指令不会正常触发. | ||
执行动作指令时,如果发生任何异常,例如无法找到目标元素,用例执行会终止并在控制台中报错. | ||
## 表达式 | ||
> 表达式和任何c系列的语言是完全一样的 | ||
例: | ||
```C | ||
1 + 2 * 3; | ||
'Hello' + ', world!'; | ||
``` | ||
### 扩展 css 选择器 | ||
Lemoncase2 默认支持 css 选择器,你可以使用: | ||
* 原生 DOM API 中的 querySelectorAll. | ||
* jQuery Sizzle ^2.3.0. | ||
* *你可以使用如 :contain(). 等原生 API 里面没有的选择器* | ||
* iframe 选择器 `<` 来选中 `<iframe>` 中的元素* | ||
```html | ||
<!-- From top frame --> | ||
<iframe id="top"> | ||
#document | ||
<html> | ||
<body> | ||
<iframe id="project"> | ||
#document | ||
<html> | ||
<body> | ||
<a href="./">link</a> <!-- select it. --> | ||
<b>link</b> | ||
</body> | ||
</html> | ||
</iframe> | ||
</body> | ||
</html> | ||
</iframe> | ||
``` | ||
* `iframe < iframe < a` | ||
* `* < * < a` | ||
* `#top < #project < a` | ||
* `* < #project < a:contain(link)` | ||
### 选择器操作符 | ||
`<# [selector:string] />` | ||
```C | ||
// 返回符合选择器的元素的数量. | ||
// <div id="link" class="case">Text</div> | ||
log <# 'div'/>; // Output 1 | ||
log <# '#link'/>; // Output 1 | ||
log <# '#no'/>; // Output 0 | ||
``` | ||
`<@ [selector:string] />` | ||
```C | ||
// 获取一个符合选择器的 HTML 元素的内容. | ||
// 返回字符串或 `false` ,如果没有匹配到任何元素. | ||
// <div id="link" class="case">Text</div> | ||
log <@ 'div'/>; // 输出 Text | ||
log <@ '#link'/>; // 输出 Text | ||
log <@ '#no'/>; // 输出 false | ||
``` | ||
`<! [selector:string] />` | ||
```C | ||
// 检查元素是否可见. | ||
// 返回 `true` 如果元素存在并且可见. | ||
// 否则返回 `false` | ||
// <div id="link" class="case">Text</div> | ||
// <div id="link2" style="display:none">Text</div> | ||
log <@ 'a'/>; // 返回 false | ||
log <@ 'div'/>; // 返回 true | ||
log <@ '#link2'/>; // 返回 false | ||
``` | ||
### 比较操作符 | ||
> 比较操作符左右的两个表达式,并返回 true 或 false. | ||
`[exp_A:string] ~~ [exp_B:string|RegExp]` | ||
* exp_B 如果不是字符串或正则,返回 false. | ||
* exp_A 如果不是字符串,返回 false. | ||
* exp_A 如果不符合正则 exp_B 则返回 false. | ||
* exp_A 字符串中如果包含字符串 exp_B 则返回 true. | ||
* exp_A 符合正则 exp_B 则返回 true. | ||
`[exp_A:string] !~ [exp_B:string|RegExp]` | ||
* 等同于 !(exp_A ~~ exp_B). | ||
# 作用域 | ||
* `全局作用域` 全局的变量哪里都能访问. | ||
* `过程 / 函数 作用域` 变量只有在过程的生命周期内有效. | ||
## 内置过程 | ||
* number(any): number | ||
* bool(any): boolean | ||
* length(str?: string): number | ||
* charAt(string, index): string | ||
* indexOf(string, string): number | ||
* substr(string, index): string | ||
* min(num1: number, num2: number): number | ||
* max(num1: number, num2: number): number | ||
* random(seed?: regexp): string | ||
* abs(num: number): number | ||
* ceil(num: number): number | ||
* floor(num: number): number | ||
* round(num: number): number | ||
* format(date: Date): string | ||
* now(): number | ||
# 例子 | ||
你要的Hello, world在这里. | ||
## Hello, world | ||
```C | ||
process main { | ||
log 'hello world'; | ||
} | ||
``` | ||
## 通常的用法 | ||
只运行一次的用例. | ||
```C | ||
#TIMES 1 | ||
process main { | ||
jumpto '[URL]'; | ||
wait 2000; | ||
... | ||
[statement] | ||
... | ||
} | ||
``` | ||
## 测试一个用户注册页面 | ||
```C | ||
#TIMES 1 | ||
#INTERVAL 3000 | ||
process main { | ||
jumpto '/#/register'; | ||
wait 2000; | ||
// There are 5 text boxes. | ||
assert <#'#userInfoFrom input'/> === 5; | ||
// There is a captcha svg. | ||
assert <!"img.pull-right"/>; | ||
// There is a login button. | ||
assert <!"#userInfoFrom > button.btn"/>; | ||
// There is a home button. | ||
assert <@"#global-back-button"/> ~~ 'glyphicon-home'; | ||
userNameRule = "#name-rule > div"; | ||
// Input username length < 6 | ||
input "#account-name" by '12345'; | ||
assert <@userNameRule/> ~~ '不少于6个字符'; | ||
// Input username length > 16 | ||
input "#account-name" by /\w{17}/; | ||
assert <@userNameRule/> ~~ '不超过16个字符'; | ||
// Username is blank | ||
input "#account-name" by ''; | ||
assert <@userNameRule/> ~~ '用户名不为空'; | ||
// Username is repeat. | ||
input "#account-name" by 'active'; | ||
click "#account-email"; | ||
assert <!"#name-repeat"/> && <@"#name-repeat"/> ~~ '用户名重复' in 2000; | ||
// Blank email. | ||
emailRule = "#email-rule > div"; | ||
input "#account-email" by ''; | ||
assert <@emailRule/> ~~ '邮箱不为空'; | ||
// Error email | ||
input "#account-email" by 'fdsf'; | ||
assert <@emailRule/> ~~ '请输入正确格式的邮箱'; | ||
// Repeat email | ||
input "#account-email" by 'lichao@or-change.cn'; | ||
click "#account-password"; | ||
assert <!"#emial-repeat"/> && <@"#emial-repeat"/> ~~ '邮箱重复' in 2000; | ||
// Input password length < 8 | ||
input "#account-password" by /\w{1,7}/; | ||
assert <@"#password-rule > div"/> ~~ '不少于8个字符'; | ||
// Input password length >20 | ||
input "#account-password" by /\w{20,}/; | ||
assert <@"#password-rule > div"/> ~~ '不超过20个字符'; | ||
// Blank password | ||
input "#account-password" by ' '; | ||
assert <@"#password-rule > div"/> ~~ '密码不为空'; | ||
// Error char. | ||
input "#account-password" by '测试测试测试测试'; | ||
assert <@"#password-rule > div"/> ~~ '您输入了非法字符'; | ||
// Password !== Confirm | ||
password = /\w{10}/; | ||
input "#account-password" by password; | ||
input "#account-password-confirm" by password + 'a'; | ||
assert <@"#confirm-rule > div"/> ~~ '两次输入不一致'; | ||
} | ||
``` | ||
## api | ||
This main exported function takes a lc2 code string and | ||
@@ -2,0 +351,0 @@ returns an abstract syntax tree |
Sorry, the diff of this file is not supported yet
44597
277
366