/// <summary> /// For code block nodes, each output identifier of an output port is mapped. /// For an example, "p = 1" would have its internal identifier renamed to /// "pXXXX", where "XXXX" is the GUID of the code block node. This mapping is /// done to ensure the uniqueness of the output variable name. /// </summary> /// <param name="portIndex">Output port index</param> /// <param name="forRawName">Set this parameter to true to retrieve the /// original identifier name "p". If this parameter is false, the mapped /// identifer name "pXXXX" is returned instead.</param> /// <returns></returns> private IdentifierNode GetAstIdentifierForOutputIndexInternal(int portIndex, bool forRawName) { var statement = GetStatementForOutput(portIndex); if (statement == null) return null; var binExprNode = statement.AstNode as BinaryExpressionNode; if (binExprNode == null || (binExprNode.LeftNode == null)) return null; var identNode = binExprNode.LeftNode as IdentifierNode; if (identNode == null) return null; var mappedIdent = NodeUtils.Clone(identNode); if (!forRawName) { var identMapper = new IdentifierInPlaceMapper(libraryServices.LibraryManagementCore, ShouldBeRenamed, LocalizeIdentifier); mappedIdent.Accept(identMapper); } return mappedIdent as IdentifierNode; }
private void SetPreviewVariable(IEnumerable<Node> parsedNodes) { previewVariable = null; if (parsedNodes == null || (!parsedNodes.Any())) return; IdentifierNode identifierNode = null; foreach (var statement in parsedNodes.Reverse().OfType<BinaryExpressionNode>()) { identifierNode = statement.LeftNode as IdentifierNode; if (identifierNode != null) // Found the identifier... { // ... that is not a temporary variable, take it! if (!tempVariables.Contains(identifierNode.Value)) break; } } if (identifierNode == null) return; var duplicatedNode = new IdentifierNode(identifierNode); var identMapper = new IdentifierInPlaceMapper(libraryServices.LibraryManagementCore, ShouldBeRenamed, LocalizeIdentifier); duplicatedNode.Accept(identMapper); // Of course, if we just needed "duplicatedNode.Value" we would not // have to clone the original "IdentifierNode". In addition to // renaming the variable, we also need to keep the array indexer // (e.g. the "previewVariable" should be "arr[2][3]" instead of just // "arr") to obtain the correct value for that particular array // element. The best way to keep these array indexers, naturally, is // to use "IdentifierNode.ToString" method, as in: // // previewVariable = duplicatedNode.ToString(); // // But the problem now is, "ILiveRunner.InspectNodeValue" method can // only return a valid RuntimeMirror if "previewVariable" contains // variable name (i.e. "arr") and nothing else (e.g. "arr[2][3]"). // For now, simply set the "previewVariable" to just the array name, // instead of the full expression with array indexers. // previewVariable = duplicatedNode.Value; }
internal override IEnumerable<AssociativeNode> BuildAst(List<AssociativeNode> inputAstNodes, CompilationContext context) { //Do not build if the node is in error. if (State == ElementState.Error) { return Enumerable.Empty<AssociativeNode>(); } var identMapper = new IdentifierInPlaceMapper(libraryServices.LibraryManagementCore, ShouldBeRenamed, LocalizeIdentifier); var resultNodes = new List<AssociativeNode>(); // Define unbound variables if necessary if (inputIdentifiers != null && inputAstNodes != null && inputIdentifiers.Count == inputAstNodes.Count) { var initStatments = inputIdentifiers.Zip(inputAstNodes, (ident, rhs) => { var identNode = AstFactory.BuildIdentifier(ident); if (context != CompilationContext.NodeToCode) identNode.Accept(identMapper); return AstFactory.BuildAssignment(identNode, rhs); }); resultNodes.AddRange(initStatments); } foreach (var astNode in codeStatements.Select(stmnt => NodeUtils.Clone(stmnt.AstNode))) { if (context != CompilationContext.NodeToCode) { (astNode as AssociativeNode).Accept(identMapper); } resultNodes.Add(astNode as AssociativeNode); } return resultNodes; }