/// <summary> /// Pre-compiles DS code in code block node, /// checks for syntax, converts non-assignments to assignments, /// stores list of AST nodes, errors and warnings /// Evaluates and stores list of unbound identifiers /// </summary> /// <param name="priorNames"></param> /// <param name="parseParams"> container for compilation related parameters </param> /// <param name="elementResolver"> classname resolver </param> /// <returns> true if code compilation succeeds, false otherwise </returns> public static bool PreCompileCodeBlock(Core core, ref ParseParam parseParams, IDictionary <string, string> priorNames = null) { string postfixGuid = parseParams.PostfixGuid.ToString().Replace("-", "_"); // Parse code to generate AST and add temporaries to non-assignment nodes List <AssociativeNode> astNodes; List <AssociativeNode> comments; ParseUserCode(core, parseParams.OriginalCode, postfixGuid, out astNodes, out comments); parseParams.AppendErrors(core.BuildStatus.Errors); if (parseParams.Errors.Count() > 0) { return(false); } // Catch the syntax errors and errors for unsupported // language constructs thrown by compile expression parseParams.AppendWarnings(core.BuildStatus.Warnings); var warnings = Check(astNodes); parseParams.AppendWarnings(warnings); parseParams.AppendParsedNodes(astNodes.Where(n => !n.skipMe)); parseParams.AppendComments(comments); // Compile the code to get the resultant unboundidentifiers // and any errors or warnings that were caught by the compiler and cache them in parseParams return(CompileCodeBlockAST(core, parseParams, priorNames)); }
private static bool CompileCodeBlockAST(Core core, ParseParam parseParams) { Dictionary <int, List <VariableLine> > unboundIdentifiers = new Dictionary <int, List <VariableLine> >(); IEnumerable <BuildData.WarningEntry> warnings = null; ProtoCore.BuildStatus buildStatus = null; try { int blockId = ProtoCore.DSASM.Constants.kInvalidIndex; CodeBlockNode codeblock = new CodeBlockNode(); List <AssociativeNode> nodes = new List <AssociativeNode>(); foreach (var i in parseParams.ParsedNodes) { AssociativeNode assocNode = i as AssociativeNode; if (assocNode != null) { nodes.Add(NodeUtils.Clone(assocNode)); } } codeblock.Body.AddRange(nodes); bool parsingPreloadFlag = core.IsParsingPreloadedAssembly; bool parsingCbnFlag = core.IsParsingPreloadedAssembly; core.IsParsingPreloadedAssembly = false; core.IsParsingCodeBlockNode = true; core.ResetForPrecompilation(); buildStatus = PreCompile(string.Empty, core, codeblock, out blockId); core.IsParsingCodeBlockNode = parsingCbnFlag; core.IsParsingPreloadedAssembly = parsingPreloadFlag; parseParams.AppendErrors(buildStatus.Errors); parseParams.AppendWarnings(buildStatus.Warnings); if (buildStatus.ErrorCount > 0) { return(false); } warnings = buildStatus.Warnings; // Get the unboundIdentifiers from the warnings GetInputLines(parseParams.ParsedNodes, warnings, unboundIdentifiers); foreach (KeyValuePair <int, List <VariableLine> > kvp in unboundIdentifiers) { foreach (VariableLine vl in kvp.Value) { parseParams.AppendUnboundIdentifier(vl.variable); } } return(true); } catch (Exception) { buildStatus = null; return(false); } }
public void ReproMAGN3603() { string code = @"a = 1 + (2 * 3); b = (1 + 2) * 3; c = 1 + 2 * 3;"; ElementResolver elementResolver = new ElementResolver(); ParseParam parseParam = new ParseParam(Guid.NewGuid(), code, elementResolver); Assert.IsTrue(CompilerUtils.PreCompileCodeBlock(thisTest.CreateTestCore(), ref parseParam)); Assert.IsTrue(parseParam.ParsedNodes != null && parseParam.ParsedNodes.Count() > 0); var parsedNode = parseParam.ParsedNodes.ElementAt(0); BinaryExpressionNode n = parsedNode as BinaryExpressionNode; FunctionCallNode funcCall = n.RightNode as FunctionCallNode; Assert.IsTrue(n != null && funcCall != null); IdentifierNode identNode = funcCall.Function as IdentifierNode; Assert.IsTrue(identNode != null && identNode.Value == "%add"); var args = funcCall.FormalArguments; Assert.IsTrue(args.Count == 2); Assert.IsTrue(args[0] is IntNode); FunctionCallNode nestedFuncCall = args[1] as FunctionCallNode; Assert.IsTrue(nestedFuncCall != null && (nestedFuncCall.Function as IdentifierNode).Value == "%mul"); parsedNode = parseParam.ParsedNodes.ElementAt(1); n = parsedNode as BinaryExpressionNode; funcCall = n.RightNode as FunctionCallNode; Assert.IsTrue(n != null && funcCall != null); identNode = funcCall.Function as IdentifierNode; Assert.IsTrue(identNode != null && identNode.Value == "%mul"); args = funcCall.FormalArguments; Assert.IsTrue(args.Count == 2); Assert.IsTrue(args[1] is IntNode); nestedFuncCall = args[0] as FunctionCallNode; Assert.IsTrue(nestedFuncCall != null && (nestedFuncCall.Function as IdentifierNode).Value == "%add"); parsedNode = parseParam.ParsedNodes.ElementAt(2); n = parsedNode as BinaryExpressionNode; funcCall = n.RightNode as FunctionCallNode; Assert.IsTrue(n != null && funcCall != null); identNode = funcCall.Function as IdentifierNode; Assert.IsTrue(identNode != null && identNode.Value == "%add"); args = funcCall.FormalArguments; Assert.IsTrue(args.Count == 2); Assert.IsTrue(args[0] is IntNode); nestedFuncCall = args[1] as FunctionCallNode; Assert.IsTrue(nestedFuncCall != null && (nestedFuncCall.Function as IdentifierNode).Value == "%mul"); }
public void TestUnboundIdentifierInUnnamedSignedExpression() { string code = @"a*-1;"; ElementResolver elementResolver = new ElementResolver(); ParseParam parseParam = new ParseParam(Guid.NewGuid(), code, elementResolver); Assert.IsTrue(CompilerUtils.PreCompileCodeBlock(thisTest.CreateTestCore(), ref parseParam)); Assert.IsTrue(parseParam.ParsedNodes != null && parseParam.ParsedNodes.Any()); var inputIdentifier = parseParam.UnboundIdentifiers; Assert.AreEqual(1, inputIdentifier.Count); Assert.AreEqual("a", inputIdentifier.ElementAt(0).Value); }
/// <summary> /// Pre-compiles DS code in code block node, /// checks for syntax, converts non-assignments to assignments, /// stores list of AST nodes, errors and warnings /// Evaluates and stores list of unbound identifiers /// </summary> /// <param name="parseParams"></param> /// <returns></returns> public static bool PreCompileCodeBlock(Core core, ref ParseParam parseParams) { string postfixGuid = parseParams.PostfixGuid.ToString().Replace("-", "_"); // Parse code to generate AST and add temporaries to non-assignment nodes IEnumerable <ProtoCore.AST.Node> astNodes = ParseUserCode(core, parseParams.OriginalCode, postfixGuid); // Catch the syntax errors and errors for unsupported // language constructs thrown by compile expression if (core.BuildStatus.ErrorCount > 0) { parseParams.AppendErrors(core.BuildStatus.Errors); parseParams.AppendWarnings(core.BuildStatus.Warnings); return(false); } parseParams.AppendParsedNodes(astNodes); // Compile the code to get the resultant unboundidentifiers // and any errors or warnings that were caught by the compiler and cache them in parseParams return(CompileCodeBlockAST(core, parseParams)); }
private void ProcessCode(ref string errorMessage, ref string warningMessage, ElementResolver workspaceElementResolver = null) { code = CodeBlockUtils.FormatUserText(code); codeStatements.Clear(); if (string.IsNullOrEmpty(Code)) previewVariable = null; try { // During loading of CBN from file, the elementResolver from the workspace is unavailable // in which case, a local copy of the ER obtained from the CBN is used var resolver = workspaceElementResolver ?? this.ElementResolver; var parseParam = new ParseParam(GUID, code, resolver); if (CompilerUtils.PreCompileCodeBlock(libraryServices.LibraryManagementCore, ref parseParam)) { if (parseParam.ParsedNodes != null) { // Create an instance of statement for each code statement written by the user foreach (var parsedNode in parseParam.ParsedNodes) { // Create a statement variable from the generated nodes codeStatements.Add(Statement.CreateInstance(parsedNode)); } SetPreviewVariable(parseParam.ParsedNodes); } } if (parseParam.Errors != null && parseParam.Errors.Any()) { errorMessage = string.Join("\n", parseParam.Errors.Select(m => m.Message)); ProcessError(); CreateInputOutputPorts(); return; } if (parseParam.Warnings != null) { // Unbound identifiers in CBN will have input slots. // // To check function redefinition, we need to check other // CBN to find out if it has been defined yet. Now just // skip this warning. var warnings = parseParam.Warnings.Where( w => w.ID != WarningID.kIdUnboundIdentifier && w.ID != WarningID.kFunctionAlreadyDefined); if (warnings.Any()) { warningMessage = string.Join("\n", warnings.Select(m => m.Message)); } } if (parseParam.UnboundIdentifiers != null) { inputIdentifiers = new List<string>(); inputPortNames = new List<string>(); foreach (var kvp in parseParam.UnboundIdentifiers) { inputIdentifiers.Add(kvp.Value); inputPortNames.Add(kvp.Key); } } else { inputIdentifiers.Clear(); inputPortNames.Clear(); } } catch (Exception e) { errorMessage = e.Message; previewVariable = null; ProcessError(); return; } // Set the input and output ports based on the statements CreateInputOutputPorts(); }
private static bool CompileCodeBlockAST(Core core, ParseParam parseParams, IDictionary <string, string> priorNames) { var unboundIdentifiers = new Dictionary <int, List <VariableLine> >(); ProtoCore.BuildStatus buildStatus = null; try { int blockId = ProtoCore.DSASM.Constants.kInvalidIndex; bool parsingPreloadFlag = core.IsParsingPreloadedAssembly; bool parsingCbnFlag = core.IsParsingPreloadedAssembly; core.IsParsingPreloadedAssembly = false; core.IsParsingCodeBlockNode = true; core.ResetForPrecompilation(); var astNodes = parseParams.ParsedNodes; // Lookup namespace resolution map in elementResolver to rewrite // partial classnames with their fully qualified names in ASTs // before passing them for pre-compilation. If partial class is not found in map, // update Resolution map in elementResolver with fully resolved name from compiler. var reWrittenNodes = ElementRewriter.RewriteElementNames(core.ClassTable, parseParams.ElementResolver, astNodes, core.BuildStatus.LogSymbolConflictWarning); if (priorNames != null) { // Use migration rewriter to migrate old method names to new names based on priorNameHints from LibraryServices reWrittenNodes = MigrationRewriter.MigrateMethodNames(reWrittenNodes, priorNames, core.BuildStatus.LogDeprecatedMethodWarning); } // Clone a disposable copy of AST nodes for PreCompile() as Codegen mutates AST's // while performing SSA transforms and we want to keep the original AST's var codeblock = new CodeBlockNode(); var nodes = reWrittenNodes.OfType <AssociativeNode>().Select(NodeUtils.Clone).ToList(); codeblock.Body.AddRange(nodes); buildStatus = PreCompile(string.Empty, core, codeblock, out blockId); core.IsParsingCodeBlockNode = parsingCbnFlag; core.IsParsingPreloadedAssembly = parsingPreloadFlag; parseParams.AppendErrors(buildStatus.Errors); parseParams.AppendWarnings(buildStatus.Warnings); if (buildStatus.ErrorCount > 0) { return(false); } IEnumerable <BuildData.WarningEntry> warnings = buildStatus.Warnings; // Get the unboundIdentifiers from the warnings GetInputLines(parseParams.ParsedNodes, warnings, unboundIdentifiers); foreach (KeyValuePair <int, List <VariableLine> > kvp in unboundIdentifiers) { foreach (VariableLine vl in kvp.Value) { parseParams.AppendUnboundIdentifier(vl.displayName, vl.variable); } } return(true); } catch (Exception) { buildStatus = null; return(false); } }
private static bool CompileCodeBlockAST(Core core, ParseParam parseParams) { var unboundIdentifiers = new Dictionary<int, List<VariableLine>>(); ProtoCore.BuildStatus buildStatus = null; try { int blockId = ProtoCore.DSASM.Constants.kInvalidIndex; bool parsingPreloadFlag = core.IsParsingPreloadedAssembly; bool parsingCbnFlag = core.IsParsingPreloadedAssembly; core.IsParsingPreloadedAssembly = false; core.IsParsingCodeBlockNode = true; core.ResetForPrecompilation(); var astNodes = parseParams.ParsedNodes; // Lookup namespace resolution map in elementResolver to rewrite // partial classnames with their fully qualified names in ASTs // before passing them for pre-compilation. If partial class is not found in map, // update Resolution map in elementResolver with fully resolved name from compiler. var reWrittenNodes = ElementRewriter.RewriteElementNames(core.ClassTable, parseParams.ElementResolver, astNodes, core.BuildStatus.LogSymbolConflictWarning); // Clone a disposable copy of AST nodes for PreCompile() as Codegen mutates AST's // while performing SSA transforms and we want to keep the original AST's var codeblock = new CodeBlockNode(); var nodes = reWrittenNodes.OfType<AssociativeNode>().Select(NodeUtils.Clone).ToList(); codeblock.Body.AddRange(nodes); buildStatus = PreCompile(string.Empty, core, codeblock, out blockId); core.IsParsingCodeBlockNode = parsingCbnFlag; core.IsParsingPreloadedAssembly = parsingPreloadFlag; parseParams.AppendErrors(buildStatus.Errors); parseParams.AppendWarnings(buildStatus.Warnings); if (buildStatus.ErrorCount > 0) { return false; } IEnumerable<BuildData.WarningEntry> warnings = buildStatus.Warnings; // Get the unboundIdentifiers from the warnings GetInputLines(parseParams.ParsedNodes, warnings, unboundIdentifiers); foreach (KeyValuePair<int, List<VariableLine>> kvp in unboundIdentifiers) { foreach (VariableLine vl in kvp.Value) parseParams.AppendUnboundIdentifier(vl.displayName, vl.variable); } return true; } catch (Exception) { buildStatus = null; return false; } }
/// <summary> /// Pre-compiles DS code in code block node, /// checks for syntax, converts non-assignments to assignments, /// stores list of AST nodes, errors and warnings /// Evaluates and stores list of unbound identifiers /// </summary> /// <param name="parseParams"> container for compilation related parameters </param> /// <param name="elementResolver"> classname resolver </param> /// <returns> true if code compilation succeeds, false otherwise </returns> public static bool PreCompileCodeBlock(Core core, ref ParseParam parseParams) { string postfixGuid = parseParams.PostfixGuid.ToString().Replace("-", "_"); // Parse code to generate AST and add temporaries to non-assignment nodes List<AssociativeNode> astNodes; List<AssociativeNode> comments; ParseUserCode(core, parseParams.OriginalCode, postfixGuid, out astNodes, out comments); // Catch the syntax errors and errors for unsupported // language constructs thrown by compile expression if (core.BuildStatus.ErrorCount > 0) { parseParams.AppendErrors(core.BuildStatus.Errors); parseParams.AppendWarnings(core.BuildStatus.Warnings); return false; } parseParams.AppendParsedNodes(astNodes); parseParams.AppendComments(comments); // Compile the code to get the resultant unboundidentifiers // and any errors or warnings that were caught by the compiler and cache them in parseParams return CompileCodeBlockAST(core, parseParams); }
/// <summary> /// Pre-compiles Design script code in code block node. /// </summary> /// <param name="parseParams">Container for compilation related parameters</param> /// <returns>true if code compilation succeeds, false otherwise</returns> public bool PreCompileCodeBlock(ref ParseParam parseParams) { return CompilerUtils.PreCompileCodeBlock(compilationCore, ref parseParams); }
public bool TryParseCode(ref ParseParam parseParam) { return CompilerUtils.PreCompileCodeBlock(libraryCore, ref parseParam); }
private static bool CompileCodeBlockAST(Core core, ParseParam parseParams) { Dictionary<int, List<VariableLine>> unboundIdentifiers = new Dictionary<int, List<VariableLine>>(); IEnumerable<BuildData.WarningEntry> warnings = null; ProtoCore.BuildStatus buildStatus = null; try { int blockId = ProtoCore.DSASM.Constants.kInvalidIndex; CodeBlockNode codeblock = new CodeBlockNode(); List<AssociativeNode> nodes = new List<AssociativeNode>(); foreach (var i in parseParams.ParsedNodes) { AssociativeNode assocNode = i as AssociativeNode; if (assocNode != null) nodes.Add(NodeUtils.Clone(assocNode)); } codeblock.Body.AddRange(nodes); bool parsingPreloadFlag = core.IsParsingPreloadedAssembly; bool parsingCbnFlag = core.IsParsingPreloadedAssembly; core.IsParsingPreloadedAssembly = false; core.IsParsingCodeBlockNode = true; core.ResetForPrecompilation(); buildStatus = PreCompile(string.Empty, core, codeblock, out blockId); core.IsParsingCodeBlockNode = parsingCbnFlag; core.IsParsingPreloadedAssembly = parsingPreloadFlag; parseParams.AppendErrors(buildStatus.Errors); parseParams.AppendWarnings(buildStatus.Warnings); if (buildStatus.ErrorCount > 0) { return false; } warnings = buildStatus.Warnings; // Get the unboundIdentifiers from the warnings GetInputLines(parseParams.ParsedNodes, warnings, unboundIdentifiers); foreach (KeyValuePair<int, List<VariableLine>> kvp in unboundIdentifiers) { foreach (VariableLine vl in kvp.Value) parseParams.AppendUnboundIdentifier(vl.variable); } return true; } catch (Exception) { buildStatus = null; return false; } }
/// <summary> /// Pre-compiles DS code in code block node, /// checks for syntax, converts non-assignments to assignments, /// stores list of AST nodes, errors and warnings /// Evaluates and stores list of unbound identifiers /// </summary> /// <param name="core"></param> /// <param name="parseParams"> container for compilation related parameters </param> /// <param name="priorNames"></param> /// <returns> true if code compilation succeeds, false otherwise </returns> public static bool PreCompileCodeBlock(Core core, ref ParseParam parseParams, IDictionary <string, string> priorNames = null) { return(PreCompileCodeBlock(core, parseParams, priorNames)); }
private void ProcessCode(ref string errorMessage, ref string warningMessage) { code = CodeBlockUtils.FormatUserText(code); codeStatements.Clear(); if (string.IsNullOrEmpty(Code)) previewVariable = null; try { ParseParam parseParam = new ParseParam(this.GUID, code); if (Workspace.DynamoModel.EngineController.TryParseCode(ref parseParam)) { if (parseParam.ParsedNodes != null) { // Create an instance of statement for each code statement written by the user foreach (var parsedNode in parseParam.ParsedNodes) { // Create a statement variable from the generated nodes codeStatements.Add(Statement.CreateInstance(parsedNode)); } SetPreviewVariable(parseParam.ParsedNodes); } } if (parseParam.Errors != null && parseParam.Errors.Any()) { errorMessage = string.Join("\n", parseParam.Errors.Select(m => m.Message)); ProcessError(); CreateInputOutputPorts(); return; } if (parseParam.Warnings != null) { // Unbound identifiers in CBN will have input slots. // // To check function redefinition, we need to check other // CBN to find out if it has been defined yet. Now just // skip this warning. var warnings = parseParam.Warnings.Where((w) => { return w.ID != WarningID.kIdUnboundIdentifier && w.ID != WarningID.kFunctionAlreadyDefined; }); if (warnings.Any()) { warningMessage = string.Join("\n", warnings.Select(m => m.Message)); } } if (parseParam.UnboundIdentifiers != null) inputIdentifiers = new List<string>(parseParam.UnboundIdentifiers); else inputIdentifiers.Clear(); } catch (Exception e) { errorMessage = e.Message; previewVariable = null; ProcessError(); return; } // Set the input and output ports based on the statements CreateInputOutputPorts(); }