Example #1
0
        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]);
        }
Example #2
0
 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));
        }
Example #4
0
        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);
        }
Example #5
0
        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();
        }
Example #6
0
        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));
        }