示例#1
0
        private IEnumerable <Parselet> LeftSquare(Token <R> token)
        {
            var tagToken = reader.ReadToken();

            switch (tagToken.ID)
            {
            default:
                compiler.SyntaxError(tagToken, "Expected function name, subroutine, regex or a script.");
                break;

            case R.Text:
                yield return(Parselet.GetParselet("FunctionText", tagToken, AddToOutput));

                break;

            case R.Regex:
                yield return(Parselet.GetParselet("FunctionRegex", tagToken, AddToOutput));

                break;

            case R.At:
                AddToOutput(compiler.ReadScript());
                break;

            case R.Dollar:
                yield return(Parselet.GetParselet("FunctionSubroutine", tagToken, AddToOutput));

                break;
            }
        }
示例#2
0
        public static void Load(bool forceNewLoad = false)
        {
            if (loaded && !forceNewLoad)
            {
                return;
            }

            // scan the Compiler.Parselets namespace for all parselets, create instances of them store them in a dictionary
            // it's clean, it's super easy to extend. a single statement loads them all from the namespace and sets them up right
            // it's slow and may be a memory hog with many parselets
            // maybe create the instances of the parselets as needed?

#if DEBUG
            System.Diagnostics.Stopwatch timer = System.Diagnostics.Stopwatch.StartNew();
#endif

            tokenTypeParseletNameDict = new Dictionary <R, string>();
            parseletNameDict          = new Dictionary <string, Parselet>();

            var types = Assembly.GetExecutingAssembly().GetTypes().Where(t =>
                                                                         t.IsClass &&
                                                                         !t.IsNested &&   // for some reason makes sure the internal enumerable type isn't included
                                                                         !t.IsAbstract && // makes sure we don't load this base class
                                                                         t.Namespace == "Rant.Engine.Compiler.Parselets");

            foreach (var type in types)
            {
#if UNITY
                if (type.GetCustomAttributes(typeof(DefaultParseletAttribute), true).Cast <DefaultParseletAttribute>().FirstOrDefault() != null)
#else
                if (type.GetCustomAttribute <DefaultParseletAttribute>() != null)
#endif

                {
                    if (defaultParselet != null)
                    {
                        throw new RantInternalException($"Cannot define {type.Name} as default parselet: {defaultParselet.GetType().Name} is already defined as default parselet.");
                    }

                    defaultParselet = (Parselet)Activator.CreateInstance(type);
                    continue;
                }

                var instance = (Parselet)Activator.CreateInstance(type);
                // here we just hope that the parselet handles itself properly
            }

            if (defaultParselet == null)
            {
                throw new RantInternalException("Default parselet missing/not loaded.");
            }

            loaded = true;
#if DEBUG
            timer.Stop();
            Console.WriteLine($"{parseletNameDict.Count} parselets from {types.Count()} classes and {tokenTypeParseletNameDict.Count} token name associations loaded in {timer.ElapsedMilliseconds}ms");
#endif
        }
        private IEnumerable <Parselet> BlockWeight(Token <R> token)
        {
            Token <R> funcToken = null;
            var       actions   = new List <RantAction>();

            while (!reader.End)
            {
                funcToken = reader.ReadToken();

                if (funcToken.ID == R.RightParen)
                {
                    reader.SkipSpace();

                    if (!actions.Any())
                    {
                        compiler.SyntaxError(funcToken, "Expected weight value");
                    }

                    RantAction weightAction;
                    // probably a number
                    if (actions[0] is RAText)
                    {
                        if (actions.Count > 1)
                        {
                            if (!(actions[1] is RAText) || ((RAText)actions[1]).Text != "." || actions.Count != 3)
                            {
                                compiler.SyntaxError(actions[1].Range, "Invalid block weight value.");
                            }
                            weightAction = new RAText(actions[0].Range,
                                                      (actions[0] as RAText).Text +
                                                      (actions[1] as RAText).Text +
                                                      (actions[2] as RAText).Text);
                        }
                        else
                        {
                            weightAction = actions[0];
                        }
                    }
                    else
                    {
                        weightAction = new RASequence(actions, funcToken);
                    }

                    AddToOutput(weightAction);
                    yield break;
                }

                yield return(Parselet.GetParselet(funcToken, actions.Add));
            }

            // TODO: this token is "our" (the one that result is us being yielded) token. maybe have the 'fromToken' passed?
            compiler.SyntaxError(token, "Unterminated function: unexpected end of file");
        }
示例#4
0
        public static void Load(bool forceNewLoad = false)
        {
            if (loaded && !forceNewLoad)
                return;

            // scan the Compiler.Parselets namespace for all parselets, create instances of them store them in a dictionary
            // it's clean, it's super easy to extend. a single statement loads them all from the namespace and sets them up right
            // it's slow and may be a memory hog with many parselets
            // maybe create the instances of the parselets as needed?

#if DEBUG
            System.Diagnostics.Stopwatch timer = System.Diagnostics.Stopwatch.StartNew();
#endif

            tokenTypeParseletNameDict = new Dictionary<R, string>();
            parseletNameDict = new Dictionary<string, Parselet>();

            var types = Assembly.GetExecutingAssembly().GetTypes().Where(t =>
                t.IsClass &&
                !t.IsNested && // for some reason makes sure the internal enumerable type isn't included
                !t.IsAbstract && // makes sure we don't load this base class
                t.Namespace == "Rant.Engine.Compiler.Parselets");

            foreach (var type in types)
            {
#if UNITY
				if (type.GetCustomAttributes(typeof(DefaultParseletAttribute), true).Cast<DefaultParseletAttribute>().FirstOrDefault() != null)
#else
				if (type.GetCustomAttribute<DefaultParseletAttribute>() != null)
#endif

				{
					if (defaultParselet != null)
                        throw new RantInternalException($"Cannot define {type.Name} as default parselet: {defaultParselet.GetType().Name} is already defined as default parselet.");

                    defaultParselet = (Parselet)Activator.CreateInstance(type);
                    continue;
                }

                var instance = (Parselet)Activator.CreateInstance(type);
                // here we just hope that the parselet handles itself properly
            }

            if (defaultParselet == null)
                throw new RantInternalException("Default parselet missing/not loaded.");

            loaded = true;
#if DEBUG
            timer.Stop();
            Console.WriteLine($"{parseletNameDict.Count} parselets from {types.Count()} classes and {tokenTypeParseletNameDict.Count} token name associations loaded in {timer.ElapsedMilliseconds}ms");
#endif
        }
示例#5
0
        private IEnumerable <Parselet> LeftCurly(Token <R> token)
        {
            reader.SkipSpace();

            // LOOK AT ME. I'M THE COMPILER NOW
            Token <R> readToken = null;
            var       actions   = new List <RantAction>();
            var       sequences = new List <RantAction>();

            List <_ <int, double> >     constantWeights = null;
            List <_ <int, RantAction> > dynamicWeights  = null;

            while (!reader.End)
            {
                readToken = reader.ReadToken();

                // TODO: kinda stupid having this handle it's own whitespace when we have a parselet for whitespace
                if (readToken.ID == R.Whitespace)
                {
                    switch (reader.PeekType())
                    {
                    case R.RightCurly:
                    case R.Pipe:
                        continue;
                    }
                }
                else if (readToken.ID == R.LeftParen) // weight
                {
                    RantAction weightAction = null;

                    // i like this AddToOutput thing because it's just a delegate that takes in a RantAction.
                    // it can do anything with the RantAction, in this case it sets it to our weightAction
                    // :>
                    yield return(Parselet.GetParselet("BlockWeight", readToken, a => weightAction = a));

                    constantWeights = constantWeights ?? new List <_ <int, double> >();
                    dynamicWeights  = dynamicWeights ?? new List <_ <int, RantAction> >();

                    if (weightAction is RAText) // constant
                    {
                        var    strWeight = (weightAction as RAText).Text;
                        double d;

                        if (!Util.ParseDouble(strWeight, out d))
                        {
                            compiler.SyntaxError(weightAction.Range, $"Invalid weight value '{strWeight}'.");
                        }

                        constantWeights.Add(_.Create(sequences.Count, d));
                    }
                    else // dynamic
                    {
                        // TODO: there's some weird issue going on with doubles being seen as dynamic weights
                        dynamicWeights.Add(_.Create(sequences.Count, weightAction));
                    }

                    continue;
                }
                else if (readToken.ID == R.Pipe)
                {
                    // add action to block and continue
                    sequences.Add(actions.Count == 1 ? actions[0] : new RASequence(actions, readToken));
                    reader.SkipSpace();
                    actions.Clear();
                    continue;
                }
                else if (readToken.ID == R.RightCurly)
                {
                    // add action to block and return
                    sequences.Add(actions.Count == 1 ? actions[0] : new RASequence(actions, readToken));
                    AddToOutput(new RABlock(Stringe.Range(token, readToken), sequences, dynamicWeights, constantWeights));
                    yield break;
                }

                yield return(Parselet.GetParselet(readToken, actions.Add));
            }

            compiler.SyntaxError(token, "Unterminated block: unexpected end of file.");
        }