public function numberedArgs( $args, $context, $line ) { return WSData::newFromPHPVar( $context->mFrame->getNumberedArguments() ); }
/** * The core interpreter method. Evaluates a single AST node. * The $rec parameter must be increated by 1 each time the function is called * recursively. */ public function evaluateNode( $node, $rec ) { if( !$node instanceof WSParserTreeNode ) { throw new WSException( 'evaluateNode() accepts only nonterminals' ); } if( !$this->mInterpreter->checkRecursionLimit( $rec ) ) { throw new WSUserVisibleException( 'recoverflow', $this->mModuleName, $this->getLine( $node ) ); } $c = $node->getChildren(); switch( $node->getType() ) { case 'stmts': $stmts = array(); while( isset( $c[1] ) ) { array_unshift( $stmts, $c[1] ); $c = $c[0]->getChildren(); } array_unshift( $stmts, $c[0] ); foreach( $stmts as $stmt ) $res = $this->evaluateNode( $stmt, $rec + 1 ); return $res; case 'stmt': if( $c[0] instanceof WSToken ) { switch( $c[0]->type ) { case 'leftcurly': return $this->evaluateNode( $c[1], $rec + 1 ); case 'if': $cond = $this->evaluateNode( $c[2], $rec + 1 ); if( $cond->toBool() ) { return $this->evaluateNode( $c[4], $rec + 1 ); } else { if( isset( $c[6] ) ) { return $this->evaluateNode( $c[6], $rec + 1 ); } else { return new WSData(); } } case 'for': $array = $this->evaluateNode( $c[4], $rec + 1 ); if( !$array->isArray() ) throw new WSUserVisibleException( 'invalidforeach', $this->mModuleName, $c[0]->line ); $last = new WSData(); $lvalues = $c[2]->getChildren(); foreach( $array->data as $key => $item ) { // <forlvalue> ::= <lvalue> | <lvalue> colon <lvalue> if( count( $lvalues ) > 1 ) { $this->setVar( $lvalues[0], WSData::newFromPHPVar( $key ), $rec ); $this->setVar( $lvalues[2], $item, $rec ); } else { $this->setVar( $lvalues[0], $item, $rec ); } try { $last = $this->evaluateNode( $c[6], $rec + 1 ); } catch( WSUserVisibleException $e ) { if( $e->getExceptionID() == 'break' ) break; elseif( $e->getExceptionID() == 'continue' ) continue; else throw $e; } } return $last; case 'try': try { return $this->evaluateNode( $c[1], $rec + 1 ); } catch( WSUserVisibleException $e ) { if( $e instanceof WSControlException ) { throw $e; } else { $this->setVar( $c[4], new WSData( WSData::DString, $e->getExceptionID() ), $rec ); return $this->evaluateNode( $c[6], $rec + 1 ); } } default: throw new WSException( "Unknown keyword: {$c[0]->type}" ); } } else { return $this->evaluateNode( $c[0], $rec + 1 ); } case 'exprreturn': switch( $c[0]->value ) { case 'return': if( isset( $c[1] ) ) { $retval = $this->evaluateNode( $c[1], $rec + 1 ); $empty = false; } else { $retval = new WSData(); $empty = true; } throw new WSReturnException( $retval, $empty ); case 'append': if( $this->mListOutput ) { throw new WSUserVisibleException( 'appendyield', $this->mModuleName, $c[0]->line ); } $this->mOutput = WSData::sum( $this->mOutput, $this->evaluateNode( $c[1], $rec + 1 ), $this->mModuleName, $c[0]->line ); break 2; case 'yield': if( $this->mOutput->type != WSData::DNull ) { throw new WSUserVisibleException( 'appendyield', $this->mModuleName, $c[0]->line ); } $this->mListOutput[] = $this->evaluateNode( $c[1], $rec + 1 ); break 2; default: throw new WSException( "Unknown return keyword: {$c[0]->value}" ); } case 'exprset': $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[1]->line ); if( $c[1]->value == '=' ) { $new = $this->evaluateNode( $c[2], $rec + 1 ); $this->setVar( $c[0], $new, $rec ); return $new; } else { $old = $this->getVar( $c[0], $rec, false ); $new = $this->evaluateNode( $c[2], $rec + 1 ); $new = $this->getValueForSetting( $old, $new, $c[1]->value, $c[1]->line ); $this->setVar( $c[0], $new, $rec ); return $new; } case 'exprtrinary': $cond = $this->evaluateNode( $c[0], $rec + 1 ); if( $cond->toBool() ) { return $this->evaluateNode( $c[2], $rec + 1 ); } else { return $this->evaluateNode( $c[4], $rec + 1 ); } case 'exprlogical': $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[1]->line ); $arg1 = $this->evaluateNode( $c[0], $rec + 1 ); switch( $c[1]->value ) { case '&': if( !$arg1->toBool() ) return new WSData( WSData::DBool, false ); else return $this->evaluateNode( $c[2], $rec + 1 ); case '|': if( $arg1->toBool() ) return new WSData( WSData::DBool, true ); else return $this->evaluateNode( $c[2], $rec + 1 ); case '^': $arg2 = $this->evaluateNode( $c[2], $rec + 1 ); return new WSData( WSData::DBool, $arg1->toBool() xor $arg2->toBool() ); default: throw new WSException( "Invalid logical operation: {$c[1]->value}" ); } case 'exprequals': case 'exprcompare': $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[1]->line ); $arg1 = $this->evaluateNode( $c[0], $rec + 1 ); $arg2 = $this->evaluateNode( $c[2], $rec + 1 ); return WSData::compareOp( $arg1, $arg2, $c[1]->value ); case 'exprsum': $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[1]->line ); $arg1 = $this->evaluateNode( $c[0], $rec + 1 ); $arg2 = $this->evaluateNode( $c[2], $rec + 1 ); switch( $c[1]->value ) { case '+': return WSData::sum( $arg1, $arg2, $this->mModuleName, $c[1]->line ); case '-': return WSData::sub( $arg1, $arg2 ); } case 'exprmul': $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[1]->line ); $arg1 = $this->evaluateNode( $c[0], $rec + 1 ); $arg2 = $this->evaluateNode( $c[2], $rec + 1 ); return WSData::mulRel( $arg1, $arg2, $c[1]->value, $this->mModuleName, $c[1]->line ); case 'exprpow': $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[1]->line ); $arg1 = $this->evaluateNode( $c[0], $rec + 1 ); $arg2 = $this->evaluateNode( $c[2], $rec + 1 ); return WSData::pow( $arg1, $arg2 ); case 'exprkeyword': $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[1]->line ); $arg1 = $this->evaluateNode( $c[0], $rec + 1 ); $arg2 = $this->evaluateNode( $c[2], $rec + 1 ); switch( $c[1]->value ) { case 'in': return WSData::keywordIn( $arg1, $arg2 ); case 'contains': return WSData::keywordIn( $arg2, $arg1 ); default: throw new WSException( "Invalid keyword: {$c[1]->value}" ); } case 'exprinvert': $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[0]->line ); $arg = $this->evaluateNode( $c[1], $rec + 1 ); return WSData::boolInvert( $arg ); case 'exprunary': $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[0]->line ); $arg = $this->evaluateNode( $c[1], $rec + 1 ); if( $c[0]->value == '-' ) return WSData::unaryMinus( $arg ); else return $arg; case 'exprfunction': // <exprFunction> ::= <funcid> leftbracket <commaListPlain> rightbracket | <funcid> leftbracket rightbracket // <exprFunction> ::= <varfunc> leftbracket <lvalue> rightbracket | <exprAtom> // <varfunc> ::= isset | delete // <funcid> ::= id | <exprAtom> doublecolon id | self doublecolon id $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[1]->line ); if( $c[0]->getType() == 'funcid' ) { if( $c[2] instanceof WSParserTreeNode ) { $args = $this->parseArray( $c[2], $rec, $dummy ); } else { $args = array(); } $idch = $c[0]->getChildren(); if( count( $idch ) == 1 ) { $funcname = $idch[0]->value; if( isset( self::$mBuiltInFunctions[$funcname] ) ) { $func = self::$mBuiltInFunctions[$funcname]; return $this->$func( $args, $idch[0]->line ); } else { return WSLibrary::callFunction( $funcname, $args, $this, $idch[0]->line ); } } else { $funcname = $idch[2]->value; if( $idch[0] instanceof WSToken ) { // self::function() $module = $this->mModule; } else { // "ModuleName"::function() $module = $this->evaluateNode( $idch[0], $rec + 1 )->toString(); } return $this->mInterpreter->invokeUserFunctionFromModule( $module, $funcname, $args, $this, $idch[1]->line ); } } else { $type = $c[0]->mChildren[0]->value; switch( $type ) { case 'isset': $val = $this->getVar( $c[2], $rec, true ); return new WSData( WSData::DBool, $val !== null ); case 'delete': $this->deleteVar( $c[2], $rec ); return new WSData(); default: throw new WSException( "Unknown keyword: {$type}" ); } } case 'expratom': if( $c[0] instanceof WSParserTreeNode ) { if( $c[0]->getType() == 'atom' ) { list( $val ) = $c[0]->getChildren(); switch( $val->type ) { case 'string': return new WSData( WSData::DString, $val->value ); case 'int': return new WSData( WSData::DInt, $val->value ); case 'float': return new WSData( WSData::DFloat, $val->value ); case 'true': return new WSData( WSData::DBool, true ); case 'false': return new WSData( WSData::DBool, false ); case 'null': return new WSData(); } } else { return $this->getVar( $c[0], $rec ); } } else { switch( $c[0]->type ) { case 'leftbracket': return $this->evaluateNode( $c[1], $rec + 1 ); case 'leftsquare': case 'leftcurly': $arraytype = null; $array = $this->parseArray( $c[1], $rec + 1, $arraytype ); return new WSData( $arraytype, $array ); case 'break': throw new WSControlException( 'break', $this->mModuleName, $c[0]->line ); case 'continue': throw new WSControlException( 'continue', $this->mModuleName, $c[0]->line ); } } default: $type = $node->getType(); throw new WSException( "Invalid node type passed to evaluateNode(): {$type}" ); } }
public function split( $args, $context, $line ) { $list = explode( $args[1]->toString(), $args[0]->toString() ); return WSData::newFromPHPVar( $list ); }