/// <summary> /// Determine that argument is optional in given call. /// </summary> /// <param name="call">Call which argument is tested.</param> /// <param name="argument">Argument which is tested.</param> /// <returns><c>true</c> if argument is optional, <c>false</c> otherwise.</returns> private bool isOptionalArgument(INodeAST call, INodeAST argument) { var provider = call.Source.CompilationInfo.GetProvider(call); var index = call.GetArgumentIndex(argument); return(provider.IsOptionalArgument(index + 1)); }
/// <summary> /// Get type registered for value represented by given node /// </summary> /// <param name="node">Node which type is needed</param> /// <returns>Type of value represented by node if registered, <c>null</c> otherwise</returns> internal TypeDescriptor GetNodeType(INodeAST node) { TypeDescriptor result; _nodeTypes.TryGetValue(node, out result); return(result); }
/// <summary> /// Handler called for every node that is removed (recursively from removedNode to descendants). /// </summary> /// <param name="view">View where node has been removed.</param> /// <param name="removedNode">Node that has been removed.</param> /// <param name="alreadyRemovedChild">Child that has been already removed.</param> private void onNodeRemoved(ExecutionView view, INodeAST removedNode, INodeAST alreadyRemovedChild = null) { if (removedNode == null) { return; } var context = EditContext(view); if (context.IsRemoved(removedNode)) { //we have already registered remove action return; } //report node removing context.NodeRemoved(removedNode); //report parent removing to all children foreach (var removedChild in removedNode.AllChildren) { if (removedChild != alreadyRemovedChild) { onParentRemoved(view, removedChild); } } }
/// <summary> /// Gets the ascendant subsequences. /// </summary> /// <param name="node">The node.</param> /// <returns>List<ISeqAST>.</returns> private List <ISeqAST> getAscendantSubsequences(INodeAST node) { var result = new List <ISeqAST>(); var currentSeq = node.ContainingSequence; while (currentSeq != null) { result.Add(currentSeq); if (currentSeq.ContainingNode == null) { break; } var currentNode = currentSeq.ContainingNode; while (currentNode.Parent != null) { currentNode = currentNode.Parent; } currentSeq = currentNode.ContainingSequence; } result.Reverse(); return(result); }
/// <summary> /// Finds the shift lines. /// </summary> /// <param name="shiftedLine">The shifted line.</param> /// <param name="behindLine">The behind line.</param> /// <param name="currentShiftedLine">The current shifted line.</param> /// <param name="currentBehindLine">The current behind line.</param> private void findShiftLines(INodeAST shiftedLine, INodeAST behindLine, out INodeAST currentShiftedLine, out INodeAST currentBehindLine) { var shiftedSubq = getAscendantSubsequences(shiftedLine); var behindSubq = getAscendantSubsequences(behindLine); currentShiftedLine = shiftedLine; currentBehindLine = behindLine; var minLength = Math.Min(shiftedSubq.Count, behindSubq.Count) - 1; for (int i = 0; i <= minLength; ++i) { var currentShifted = shiftedSubq[i]; var currentBehind = behindSubq[i]; if (i == minLength || currentBehind != currentShifted) { if (currentBehind != currentShifted) { //we have to use previous node --i; } currentShiftedLine = getShiftingNode(i, shiftedSubq, currentShiftedLine); currentBehindLine = getShiftingNode(i, behindSubq, currentBehindLine); break; } } }
private string resolveRedeclarationType(VariableInfo variable, INodeAST assignedVariable, bool canUseImpicit) { var variableType = variable.Type; if (variableType == null) { throw new NotSupportedException("Cannot redeclare variable, because of missing type info"); } if (!variable.IsImplicitlyTyped || !canUseImpicit) { //keep convetion on explicit variable typing //or we cannot use implicit typing e.g. because of uninitialized variable delcaration return(variableType.TypeName); } var assignedType = _source.CompilationInfo.ResolveAssignType(assignedVariable); if (assignedType == null || assignedType.TypeName != variableType.TypeName) { //we don't know type of assignedType, or implicit type is different, //so whole type name is required return(variableType.TypeName); } //assigned type matches to variable type and implicit type convetion is used return(CSharpSyntax.ImplicitVariableType); }
public VariableLValue(VariableInfo variable, INodeAST variableNode, CompilationContext context) : base(context) { variable.AddVariableUsing(variableNode); _variable = variable; _variableNode = variableNode; }
public LiteralValue(object literal, INodeAST literalNode, CompilationContext context) : base(context) { _literal = literal; _literalNode = literalNode; _literalInfo = TypeDescriptor.Create(_literal.GetType()); }
/// <summary> /// Processes the r node. /// </summary> /// <param name="node">The node.</param> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> private bool processRNode(INodeAST node) { //require available searcher if (_searcher == null) { //new searcher is needed, based on current object if (_currentObject == null) { //object is needed for searcher creation //in current state - hierarchy has to be continuous return(false); } _searcher = createMethodSearcher(_currentObject); } //search within the searcher dispatchByNode(_searcher, node, false); if (_searcher.HasResults) { //there are possible overloads for call return(setCalledObject(node, false)); } else { //methods are not available - probably namespace //cascade is processed return(extendName(node)); } }
/// <summary> /// Sets the current object. /// </summary> /// <param name="calledObject">The called object.</param> /// <param name="currNode">The curr node.</param> /// <param name="dispatchSetter">if set to <c>true</c> [dispatch setter].</param> /// <returns><c>true</c> if current object is correctly set, <c>false</c> otherwise.</returns> private bool setCurrentObject(RValueProvider calledObject, INodeAST currNode, bool dispatchSetter) { if (calledObject != null && currNode != null && currNode.Indexer != null) { if (dispatchSetter) { //nothing to do here - setters are created in LNode value processing } else { var searcher = createMethodSearcher(calledObject); searcher.Dispatch(Naming.IndexerGetter); calledObject = resolveCall(calledObject, currNode, searcher.FoundResult); if (calledObject == null) { //indexer hasn't been found return(false); } //reset searcher, because object has been found _searcher = null; } } _currentObject = calledObject; return(true); }
/// <summary> /// Creates the setter value. /// </summary> /// <param name="currNode">The curr node.</param> /// <param name="overloadMethods">The overload methods.</param> /// <returns>SetterLValue.</returns> private SetterLValue createSetterValue(INodeAST currNode, IEnumerable <TypeMethodInfo> overloadMethods) { var overloads = overloadMethods.ToArray(); //overloading on setters is not supported if (overloads.Length > 1) { throw CSharpSyntax.ParsingException(currNode, "Cannot select setter overload for {0}", currNode.Value); } var overload = overloads[0]; if (!overload.IsStatic && _currentObject == null) { if (!_compiler.MethodInfo.HasThis) { //cannot get implicit this object return(null); } var implicitThis = _compiler.CreateImplicitThis(currNode); setCurrentObject(implicitThis, currNode, true); } var indexArguments = _compiler.GetArguments(currNode, currNode.Indexer != null); return(new SetterLValue(overloads[0], _currentObject, indexArguments, Context)); }
/// <summary> /// Determine that current node represents call root. /// </summary> /// <param name="node">Tested node</param> /// <returns><c>true</c> for call root node, <c>false</c> otherwise</returns> public static bool IsCallRoot(this INodeAST node) { var type = node.NodeType; if (type != NodeTypes.hierarchy || type != NodeTypes.call) { //only hierarchy or call can be root of call return(false); } var current = node; while (current != null) { if (current.NodeType == NodeTypes.call) { //call hierarchy has to end by call return(true); } current = current.Child; } return(false); }
/// <summary> /// Determine that given node represent expression with side effect. /// </summary> /// <param name="node">Tested node.</param> /// <returns><c>true</c> if node represent expression with side effect, <c>false</c> otherwise.</returns> private bool hasSideEffect(INodeAST node) { if (node.Value == "typeof") { return(false); } if (node.IsAssign()) { return(true); } if (node.IsConstructor()) { //constructors has side effects only if they are looked at new node return(node.Value == CSharpSyntax.NewOperator); } if (node.IsCallRoot()) { //calls has side effect only if theire complete - from hierarchy root return(true); } return(new NodeTypes[] { NodeTypes.prefixOperator, NodeTypes.postOperator }.Contains(node.NodeType)); }
/// <summary> /// Get code represented by given node. /// </summary> /// <param name="node">Node which code is needed.</param> /// <returns>Code represented by given node.</returns> private string getCode(INodeAST node) { int p1, p2; getBorderPositions(node, out p1, out p2); return(OriginalCode.Substring(p1, p2 - p1)); }
public override void AssignLiteral(object literal, INodeAST literalNode) { var storage = E.GetTemporaryVariable("const"); E.AssignLiteral(storage, literal); var builder = generateAssign(storage); //TODO set call transformation provider }
/// <summary> /// Remove node from source in given view. Is only syntactical. Should be called only after /// proper node hierarchy remove handling. /// </summary> /// <param name="view">View where source node will be removed.</param> /// <param name="node">Node that will be removed.</param> private void remove(ExecutionView view, INodeAST node) { int p1, p2; getBorderPositions(node, out p1, out p2); write(view, p1, p2, ""); }
public override void AssignReturnValue(TypeDescriptor returnedValueType, INodeAST callNode) { var storage = E.GetTemporaryVariable("ret"); var builder = E.AssignReturnValue(storage, returnedValueType); builder.RemoveProvider = new AssignRemove(callNode); generateAssign(storage); //TODO set call transformation provider }
/// <summary> /// Return number of expected operands for given node. /// </summary> /// <param name="node">Node which arity is returned.</param> /// <returns>Arity of node.</returns> public int Arity(INodeAST node) { //unary nodes are resolved in context. if (node.NodeType == NodeTypes.binaryOperator) { return(2); } return(0); }
internal SourceRemoveProvider(TransformAction action, INodeAST contextNode) { if (action == null) { throw new ArgumentNullException(); } _action = action; _contextNode = contextNode; }
/// <summary> /// Get offset before given node. /// </summary> /// <param name="node">Resolved node.</param> /// <returns>Offset before node.</returns> private int getBeforeOffset(INodeAST node) { if (node == null) { return(0); } return(node.StartingToken.Position.Offset); }
/// <summary> /// Mark given node as removed by given child. Marked node has no chance to be /// preserved and has to be removed. It is possible to recursively mark parent /// and let be removed by the parent. /// </summary> /// <param name="view">View where node has been removed.</param> /// <param name="removedNode">Node that is removed.</param> /// <param name="markingChild">Child that marked its parent as removed.</param> private void markRemoved(ExecutionView view, INodeAST removedNode, INodeAST markingChild) { //report parent removing to all children except marking child onNodeRemoved(view, removedNode, markingChild); var parent = removedNode.Parent; var parentType = parent == null ? NodeTypes.hierarchy : parent.NodeType; //detect that parent has to be marked as removed var removeParent = false; switch (parentType) { case NodeTypes.call: if (isOptionalArgument(parent, removedNode)) { removeParent = false; //removed node is optional node of its parent //check only for remaining argument delimiters var argCount = parent.Arguments.Length; if (argCount > 1) { //there is delimiter that should be also removed var argIndex = parent.GetArgumentIndex(removedNode); //last argument has leading delimiter, non last has trailing delimiter var isLastArg = argCount - 1 == argIndex; var delimiterToken = isLastArg ? removedNode.StartingToken.Previous : removedNode.EndingToken.Next; remove(view, delimiterToken); } } else { //non optional argument cannot be removed from parent //so we will remove parent removeParent = true; } break; default: removeParent = true; break; } //handle removing if (parent != null && removeParent) { markRemoved(view, parent, removedNode); } else { //removedNode is last removed node in hierarchy - remove it from source remove(view, removedNode); } }
/// <summary> /// Append call at new line after lineNode. /// </summary> /// <param name="view">View where transformation is processed.</param> /// <param name="lineNode">Node with line where call will be appended.</param> /// <param name="call">Prepended call.</param> internal void PrependCall(ExecutionView view, INodeAST lineNode, CallEditInfo call) { var callRepresentation = callToCSharp(call); ensureNamespaces(view, call); var beforeLineOffset = getBeforeOffset(lineNode); write(view, beforeLineOffset, callRepresentation); }
private INodeAST getTopNode(INodeAST node) { var currNode = node; while (currNode.Parent != null) { currNode = currNode.Parent; } return(currNode); }
internal BlockProvider(INodeAST lineNode, Source source = null) { _line = lineNode; _source = _line == null ? source : _line.Source; if (_source == null) { throw new ArgumentNullException("source"); } }
/// <summary> /// Determine that current node represents assign. /// </summary> /// <param name="node">Tested node</param> /// <returns><c>true</c> for assign nodes, <c>false</c> otherwise</returns> public static bool IsAssign(this INodeAST node) { var v = node.Value; //note that => ,<=, >= are not assigns return (v.EndsWith("=") && !v.Contains('>') && !v.Contains('<')); }
/// <summary> /// Processes the l node. /// </summary> /// <param name="currNode">The curr node.</param> /// <returns>SetterLValue.</returns> private SetterLValue processLNode(INodeAST currNode) { dispatchByNode(_searcher, currNode, true); if (_searcher.HasResults) { return(createSetterValue(currNode, _searcher.FoundResult)); } return(null); }
/// <summary> /// Rewrite given node with code representation of given value. /// </summary> /// <param name="view">View where transformation is processed.</param> /// <param name="node">Node that is rewritten.</param> /// <param name="value">Value which rewrite given node.</param> internal void Rewrite(ExecutionView view, INodeAST node, object value) { preserveSideEffect(view, node); int p1, p2; getBorderPositions(node, out p1, out p2); write(view, p1, p2, toCSharp(value)); }
/// <summary> /// Gets the shifting node. /// </summary> /// <param name="index">The index.</param> /// <param name="subqChain">The subq chain.</param> /// <param name="defaultNode">The default node.</param> /// <returns>INodeAST.</returns> private INodeAST getShiftingNode(int index, List <ISeqAST> subqChain, INodeAST defaultNode) { var i = index + 1; if (i >= subqChain.Count) { return(defaultNode); } return(getTopParent(subqChain[i].ContainingNode)); }
/// <summary> /// Gets the top parent. /// </summary> /// <param name="node">The node.</param> /// <returns>INodeAST.</returns> private INodeAST getTopParent(INodeAST node) { var current = node.Parent; while (current.Parent != null) { current = current.Parent; } return(current); }
/// <summary> /// Find position which can be used for inserting statement before nodes statement. /// </summary> /// <param name="node">Node for that is searched position for inserting previous statement.</param> /// <returns>Position before nodes statement.</returns> internal int BeforeStatementOffset(INodeAST node) { var current = node; while (current.Parent != null) { current = current.Parent; } return(current.StartingToken.Position.Offset); }