/// <summary> /// Converts "standard" rules from .akk to .cs. /// </summary> /// <remarks> /// This method must come before the conversion to Facts.QueryTvar<Tvar>(). /// </remarks> private static string ConvertRegularRules(string line, string space) { if (Util.Depth(line) == 0) { line = TransformMethod.CreateMainRule(line, space); } return(line); }
/// <summary> /// Applies transformation rules to the input line. /// </summary> private static string Convert(string line, string previousLine, string fileName, string tableMatchLine, string currentRuleType, string docNameSpace) { // Perform general syntactic replacements line = line.Replace("|~", "^"); line = line.Replace("&", "&&").Replace("|", "||"); line = line.Replace("...", "("); line = line.Replace("<>", "!="); // Currency values line = Util.RemoveCurrencyStyling(line); // Stub() line = Regex.Replace(line, @"Stub\(\)", "new " + currentRuleType + "(Hstate.Stub)"); // Process question-related metadata and declared assumptions Questions.GatherMetadata(line, previousLine, fileName, docNameSpace); line = Assumptions.Process(line, docNameSpace); // Regex part const string word = @"[-!\+\*/A-Za-z0-9\.;\(\),""'_<>=&| %]+"; // Convert rules and dates line = ConvertRegularRules(line, docNameSpace); line = ConvertRuleTables(line, currentRuleType, tableMatchLine, word); // Facts.QueryTvar<Tvar>() // line = TransformMethod.QueryTvarTransform(line, docNameSpace, previousLine); // can be used to generate c# custom attributes line = TransformMethod.QueryTvarTransform(line, docNameSpace); // IfThen() line = Regex.Replace(line, @"if (?<txt>" + word + @") then (?<txt2>[-!\+\*/A-Za-z0-9\.;\(\),""'_<>= ]+)", "IfThen(${txt}, ${txt2})"); // Higher-order set functions line = Regex.Replace(line, @"\.(?<quant>(Exists|ForAll|Filter|Sum|Min|Max|OptimalSubset))\((?<fcn>[a-zA-Z0-9\(\)\._,\! ]+)\)", ".${quant}( _ => ${fcn})"); return(line); }
/// <summary> /// Iterates through the .akk file line by line and converts it to C#. /// </summary> public static string CompilerOutput(string file) { // Mutable variables int ruleCount = 0; int lastLineDepth = 0; int parenCount = 0; bool isCommentBlock = false; bool isRulePart = false; string rulePart = ""; List <string> subrules = new List <string>(); string previousLine = ""; // Keeps track of the previous .akk line string tableMatchLine = ""; // Rule input that must be matched in a table string currentRuleType = ""; // For main rules and subrule string mainRuleType = ""; // For main rules string methodCacheLine = ""; // Creates line that caches method results bool cacheRule = false; // Should method results be cached? string unitTests = ""; // Accumulates lines as they are processed // First pass: get the document namespace string docNameSpace = Boilerplate.GetDocNameSpace(file); // Second pass: get the file metadata string result = Boilerplate.InitialBoilerplate(file, docNameSpace); // Third pass: parse the rules, line by line StreamReader stream = new StreamReader(file); string line; while ((line = stream.ReadLine()) != null) { line = line.Replace("\t", " "); int depth = Util.Depth(line); // Handle commented lines, comment blocks, and mid-line comments if (!isCommentBlock && Util.IsCommentBlockLine(line)) { isCommentBlock = true; } else if (isCommentBlock && Util.IsCommentBlockLine(line)) { isCommentBlock = false; continue; } if (isCommentBlock || Util.IsComment(line)) { previousLine = line; // Get previous line, to capture any question text continue; } line = Util.DeComment(line); // Create unit test from .akk if (Tests.IsTestLine(line)) { unitTests += Tests.ProcessTestLine(line); continue; } // Process the line if (Util.IsMainRule(line)) // Begin a new rule { // Close previous rule if (ruleCount != 0) { result += Util.ReorderSubrules(subrules, mainRuleType, cacheRule, methodCacheLine); result += Util.EndRule; } subrules.Clear(); // Process current line cacheRule = false; result += Convert(line, previousLine, file, tableMatchLine, currentRuleType, docNameSpace); // Detect whether this is a function that needs to be cached const string wrd = TransformMethod.wrd; const string typs = TransformMethod.typs; if (Regex.Match(line, @"(?<typ>" + typs + @")(?<sym>Sym)?(?<quest>\?)? (?<fcn>" + wrd + @")\((?<argtyp1>" + wrd + @" )(?<arg1>" + wrd + @")(?<comma1>, ?)?(?<argtyp2>" + wrd + @" )?(?<arg2>" + wrd + @")?(?<comma2>, ?)?(?<argtyp3>" + wrd + @" )?(?<arg3>" + wrd + @")?\) =").Success) { cacheRule = true; methodCacheLine = TransformMethod.MethodCacheLine(line, docNameSpace); } // Set flag variables ruleCount++; parenCount = 0; currentRuleType = Util.ExtractRuleType(line); mainRuleType = currentRuleType; totalRuleCount++; } else // Add ordinary rule conditions { string snippet = ""; if (depth > 0) { isRulePart = true; } // Identify return type of subrule if (depth == 1 && Util.IsDeclaration(line)) { currentRuleType = Util.ExtractRuleType(line); } // Deal with parentheses if (line.Trim() == "...") { parenCount++; } int closingParensNeeded = Math.Min(lastLineDepth - depth, parenCount); if (parenCount > 0 && closingParensNeeded > 0) { parenCount = parenCount - closingParensNeeded; snippet += Util.ClosingParens(closingParensNeeded, lastLineDepth); } // Handle rule tables if (line.Trim().StartsWith("match")) { tableMatchLine = line; } // Convert the line items (to main rule or subrule) snippet += " " + Convert(line, previousLine, file, tableMatchLine, currentRuleType, docNameSpace) + "\r\n"; if (isRulePart) { rulePart += snippet; } else { result += snippet; } } if (Util.IsBlank(line)) // Blank lines { // Reset subrule flag and add subrule to subrule list isRulePart = false; if (rulePart != "") { subrules.Add(rulePart); } rulePart = ""; } else { SlocCount++; // Doesn't count test case lines (by design) } lastLineDepth = depth; } stream.Close(); // Close the final method result += Util.ReorderSubrules(subrules, mainRuleType, cacheRule, methodCacheLine); result += Util.EndRule; // Close the class/namespace, and add the unit tests result += Boilerplate.ClassAndNamespaceClose; string unitTestNameSpace = docNameSpace; result += Tests.WriteUnitTests(unitTests, unitTestNameSpace); return(result); }