public void SetVariableFromOutsideProgram() { s_output = new List <string>(); TextReader programString = File.OpenText("code50.txt"); // print(MAGIC_NUMBER) FunctionDefinition[] funcs = new FunctionDefinition[1]; funcs[0] = new FunctionDefinition("void", "print", new string[] { "string" }, new string[] { "text" }, new ExternalFunctionCreator.OnFunctionCall(print), FunctionDocumentation.Default() ); VariableDefinition[] vars = new VariableDefinition[3]; vars[0] = new VariableDefinition("MAGIC_NUMBER", new ReturnValue(43)); vars[1] = new VariableDefinition("MAGIC_BOOL", new ReturnValue(true)); vars[2] = new VariableDefinition("MAGIC_STRING", new ReturnValue("hej")); SprakRunner program = new SprakRunner(programString, funcs, vars); program.run(); Assert.AreEqual(0, program.getRuntimeErrorHandler().getErrors().Count); Assert.AreEqual("43", s_output[0]); Assert.AreEqual("true", s_output[1]); Assert.AreEqual("hej", s_output[2]); }
static FunctionDefinition GetPrintFunction() { return(new FunctionDefinition( "void", "print", new string[] { "string" }, new string[] { "text" }, o => { Console.WriteLine((string)o[0]); return new object(); }, FunctionDocumentation.Default())); }
private FunctionDocumentation BakeFunctionDocumentation([NotNull] FunctionDocumentation function) { var purposeBuilder = new StringBuilder(); purposeBuilder.Append(function.Purpose.Transform(To.SentenceCase)); if (purposeBuilder[purposeBuilder.Length - 1] != '.') { purposeBuilder.Append('.'); } var bakedParameters = function.Parameters.Select(p => BakeParameterDocumentation(function, p)).ToList(); return(new FunctionDocumentation(function.Name, purposeBuilder.ToString(), bakedParameters, function.Group)); }
public void CallingFunctionWithWrongArgumentType_MANUAL_FUNCTION_DEFINITION() { TextReader programString = File.OpenText("code72.txt"); FunctionDefinition[] functionDefinitions = new FunctionDefinition[] { new FunctionDefinition( "number", "ThisFunctionTakesANumber", new string[] { "number" }, new string[] { "x" }, ThisFunctionTakesANumber, FunctionDocumentation.Default()), GetPrintFunction() }; SprakRunner program = new SprakRunner(programString, functionDefinitions); program.run(); Assert.AreEqual(0, program.getCompileTimeErrorHandler().getErrors().Count); }
static void Main(string[] args) { string filename = "../Program1"; if (args.Length > 0) { filename = args[0]; } TextReader tr = File.OpenText(filename); //StringReader programString = new StringReader("g()\nfloat g() {\n print(42)\n }"); FunctionDefinition[] functionDefinitions = new FunctionDefinition[] { new FunctionDefinition("void", "print", new string[] { "string" }, new string[] { "text" }, print, FunctionDocumentation.Default()) }; SprakRunner runner = new SprakRunner(tr, functionDefinitions); bool success = runner.Start(); if (success) { while (runner.Step() == InterpreterTwo.Status.OK) { } } Console.WriteLine("OUTPUT: "); foreach (string s in m_output) { Console.WriteLine(s); } //runner.printTree(true); //Console.In.ReadLine(); }
public void CompileAndRun() { GameTypes.D.onDLog += Console.WriteLine; output = new List <string>(); RelayTwo relay = new RelayTwo(); TableTwo programsTable = relay.CreateTable(Program.TABLE_NAME); FunctionDefinition print = new FunctionDefinition("void", "print", new string[] { "string" }, new string[] { "s" }, API_print, FunctionDocumentation.Default()); Program p1 = new Program(); p1.CreateNewRelayEntry(programsTable, "Program"); p1.Init(new ProgramRunner(relay)); p1.sourceCodeContent = "print(42)"; p1.FunctionDefinitions.Add(print); p1.Compile(); Assert.AreEqual(0, p1.GetErrors().Length); for (int i = 0; i < 100; i++) { if (p1.sprakRunner.interpreter != null) { p1.Update(0.1f); } } Assert.AreEqual(1, output.Count); Assert.AreEqual("42", output[0]); }
public void ProgramWithOutputGettingHacked() { const string saveName = "SimpleHacking.json"; output = new List <string>(); FunctionDefinition print = new FunctionDefinition("void", "print", new string[] { "string" }, new string[] { "s" }, API_print, FunctionDocumentation.Default()); { SourceCode helloWorldSource = _world.sourceCodeDispenser.GetSourceCode("helloworld"); Program helloWorldProgram = _world.programRunner.CreateProgram(helloWorldSource); helloWorldProgram.FunctionDefinitions.Add(print); Character morgan = _world.tingRunner.CreateTing <Character>("Morgan", testDefaultCoordinate); morgan.programs = new Program[] { helloWorldProgram }; helloWorldProgram.Start(); WorldTestHelper.UpdateWorld(_world, 5f); Assert.AreEqual(1, output.Count); Assert.AreEqual("Hello World!", output[0]); helloWorldProgram.sourceCodeContent = "print(\"Hello Moon!\")"; _world.Save(saveName); } { _world = new World(saveName); Character morgan = _world.tingRunner.GetTing("Morgan") as Character; Assert.AreEqual(1, morgan.programs.Length); Program helloWorld = morgan.GetProgram("helloworld"); Assert.IsNotNull(helloWorld); helloWorld.FunctionDefinitions.Add(print); helloWorld.Start(); WorldTestHelper.UpdateWorld(_world, 5f); Assert.AreEqual(2, output.Count); Assert.AreEqual("Hello Moon!", output[1]); } }
static void Main(string[] args) { string filename = ""; //"../Program1"; if (args.Length > 0) { filename = args [0]; } else { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("No program file given"); return; } TextReader tr = File.OpenText(filename); //StringReader programString = new StringReader("g()\nfloat g() {\n print(42)\n }"); FunctionDefinition[] functionDefinitions = new FunctionDefinition[] { new FunctionDefinition("void", "print", new string[] { "string" }, new string[] { "text" }, print, FunctionDocumentation.Default()) }; SprakRunner runner = new SprakRunner(tr, functionDefinitions); runner.run(int.MaxValue); }
/// <summary> /// Appends the contents of a constant value node, transformed into its best-matching XMLDoc equivalent. /// </summary> /// <param name="descriptionBuilder">The builder to append to.</param> /// <param name="function">The function the node is in.</param> /// <param name="parameter">The parameter the node is in.</param> /// <param name="constantNode">The node.</param> /// <param name="greedilyConsumedNodes">Nodes that have been greedily consumed.</param> private void AppendConstantNode ( [NotNull] StringBuilder descriptionBuilder, [NotNull] FunctionDocumentation function, [NotNull] ParameterDocumentation parameter, [NotNull] XElement constantNode, [NotNull, ItemNotNull] ICollection <XNode> greedilyConsumedNodes ) { var constantName = constantNode.Value; if (constantName.StartsWith("GL_")) { // It's an enum - transform its name, and look it up var translatedName = _identifierTranslator.Translate ( constantName.Remove(0, 3) ); // Arbitrary number handling string arbitraryNumberName = null; var hasArbitraryNumberInsert = false; if (translatedName.EndsWith("i")) { translatedName = translatedName.Remove(translatedName.Length - 1); hasArbitraryNumberInsert = true; arbitraryNumberName = "i"; } var hasEmphasizedNumberInsert = constantNode.NextNode is XElement emphasisNode && (emphasisNode.Attribute("class")?.Value == "emphasis" || emphasisNode.Attribute("class")?.Value == "replaceable"); if (hasEmphasizedNumberInsert) { var nextNode = (XElement)constantNode.NextNode; arbitraryNumberName = nextNode.Value; hasArbitraryNumberInsert = true; } // See if it's followed by a number (emphasized) if (hasArbitraryNumberInsert) { // It is a number, so we'll just stick a 0 on the end as a stand-in translatedName = $"{translatedName}0"; } if (hasEmphasizedNumberInsert) { greedilyConsumedNodes.Add(constantNode.NextNode); } // See if we can find the name of the enum that the constant is in // Look up the function that the parameter is in var functionNameWithoutPrefix = new string(function.Name.SkipWhile(char.IsLower).ToArray()); var actualFunction = _apiProfile.FindFunctionWithEntrypoint(functionNameWithoutPrefix); if (actualFunction is null) { throw new InvalidOperationException ( $"Could not find a function named \"{functionNameWithoutPrefix}\"" ); } var actualParameter = actualFunction.Parameters.FirstOrDefault(p => p.Name == parameter.Name); var typeName = actualParameter?.Type.Name; if (typeName is null) { Debug.WriteLine ( $"Could not find the parameter named \"{parameter.Name}\" in " + $"\"{actualFunction.Name}\". Consider adding a name override to " + $"match the documentation." ); } if (typeName is null || _apiProfile.Enumerations.All(e => e.Name != typeName)) { var containingEnum = _apiProfile.FindContainingEnumeration(translatedName); if (containingEnum is null) { typeName = "Unknown"; } else { typeName = containingEnum.Name; } Debug.WriteLine ( $"Falling back to a manual enum type search for " + $"\"{translatedName}\"." ); } descriptionBuilder.Append ( $"<see cref=\"{typeName}.{translatedName}\"/>" ); if (hasArbitraryNumberInsert) { descriptionBuilder.Append($" (consider 0 as <i>{arbitraryNumberName}</i>)"); } } else { // It's a constant value of some sort - transform it to lower, and inline descriptionBuilder.Append ( $"<value>{constantName.Transform(To.LowerCase)}</value>" ); } }
private ParameterDocumentation BakeParameterDocumentation ( [NotNull] FunctionDocumentation function, [NotNull] ParameterDocumentation parameter ) { var readerSettings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment, IgnoreComments = true, IgnoreWhitespace = true }; var descriptionBuilder = new StringBuilder(); using (var sr = new StringReader(parameter.Description)) { using (var xr = XmlReader.Create(sr, readerSettings)) { var descriptionFragment = XDocument.Load(xr).Root; // Each node handler may consume nodes that come after it. When they do, they're placed in this list // so that they can be skipped. var greedilyConsumedNodes = new List <XNode>(); // ReSharper disable once PossibleNullReferenceException foreach (var node in descriptionFragment.Nodes()) { if (greedilyConsumedNodes.Contains(node)) { continue; } switch (node) { case XText text: { var lines = text.Value.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) { if (string.IsNullOrWhiteSpace(line)) { continue; } descriptionBuilder.AppendLine(line.Trim()); } break; } case XElement element: { if (element.Name == "math") { // This is a MathML block. We'll just write it as-is. descriptionBuilder.Append(element); break; } if (element.Attribute("class") is null) { // Some sort of weird HTML tag descriptionBuilder.Append(element); break; } var elementClass = element.GetRequiredAttribute("class").Value; switch (elementClass) { case "parameter": { AppendParameterNode(descriptionBuilder, element); break; } case "constant": { AppendConstantNode(descriptionBuilder, function, parameter, element, greedilyConsumedNodes); break; } case "replaceable": case "code": case "emphasis": { AppendEmphasisNode(descriptionBuilder, element); break; } case "citerefentry": case "function": { AppendFunctionNode(descriptionBuilder, element); break; } case "footnote": { // Skip footnotes break; } default: { throw new ArgumentOutOfRangeException ( nameof(node), $"Unrecognized element class\"{elementClass}\"." ); } } break; } default: { throw new ArgumentOutOfRangeException(nameof(node), "Unrecognized node type."); } } } } } var description = descriptionBuilder.ToString().Trim(); if (!description.EndsWith(".")) { description = $"{description}."; } return(new ParameterDocumentation(parameter.Name, description)); }