Example #1
0
        public FunctionDefinition ParseFunctionDefinition(TokenStream tokens)
        {
            PType returnType = PType.Parse(tokens);
            Token nameToken  = EnsureTokenIsValidName(tokens.Pop(), "Expected function name");

            tokens.PopExpected("(");
            List <PType> argTypes = new List <PType>();
            List <Token> argNames = new List <Token>();

            while (!tokens.PopIfPresent(")"))
            {
                if (argTypes.Count > 0)
                {
                    tokens.PopExpected(",");
                }
                argTypes.Add(PType.Parse(tokens));
                argNames.Add(EnsureTokenIsValidName(tokens.Pop(), "Invalid function arg name"));
            }
            FunctionDefinition funcDef = new FunctionDefinition(nameToken, returnType, argTypes, argNames, this.context, null);

            this.currentCodeOwner = funcDef;
            List <Executable> code = this.ParseCodeBlock(tokens, true);

            this.currentCodeOwner = null;
            funcDef.Code          = code.ToArray();
            return(funcDef);
        }
Example #2
0
        private Expression ParseEntity(TokenStream tokens)
        {
            if (tokens.IsNext("new"))
            {
                Token newToken        = tokens.Pop();
                PType typeToConstruct = PType.Parse(tokens);
                if (!tokens.IsNext("("))
                {
                    tokens.PopExpected("(");                      // intentional error if not present.
                }
                Expression constructorReference = new ConstructorReference(newToken, typeToConstruct, this.currentCodeOwner);
                return(this.ParseEntityChain(constructorReference, tokens));
            }

            if (tokens.PopIfPresent("("))
            {
                Expression expression = this.ParseExpression(tokens);
                tokens.PopExpected(")");
                return(this.ParseOutEntitySuffixes(tokens, expression));
            }

            Expression root = this.ParseEntityRoot(tokens);

            return(this.ParseOutEntitySuffixes(tokens, root));
        }
Example #3
0
        public StructDefinition ParseStructDefinition(TokenStream tokens)
        {
            Token structToken = tokens.PopExpected("struct");
            Token nameToken   = EnsureTokenIsValidName(tokens.Pop(), "Invalid struct name");

            Token parentName = null;

            if (tokens.PopIfPresent("extends"))
            {
                parentName = tokens.PopIdentifier();
            }

            List <PType> structFieldTypes = new List <PType>();
            List <Token> structFieldNames = new List <Token>();

            tokens.PopExpected("{");
            while (!tokens.PopIfPresent("}"))
            {
                PType fieldType = PType.Parse(tokens);
                Token fieldName = EnsureTokenIsValidName(tokens.Pop(), "Invalid struct field name");
                structFieldTypes.Add(fieldType);
                structFieldNames.Add(fieldName);
                tokens.PopExpected(";");
            }
            return(new StructDefinition(structToken, nameToken, structFieldTypes, structFieldNames, parentName, this.context));
        }
Example #4
0
 public void HandleData(MemBlock payload, ISender return_path, object state)
 {
     if (_sub != null)
     {
         MemBlock rest = null;
         PType.Parse(payload, out rest);
         _sub.Handle(rest, return_path);
     }
 }
Example #5
0
        private static void Init()
        {
            Dictionary <string, CoreFunction> lookup = new Dictionary <string, CoreFunction>();

            foreach (CoreFunction func in typeof(CoreFunction).GetEnumValues().Cast <CoreFunction>())
            {
                lookup[func.ToString()] = func;
            }

            returnTypes      = new Dictionary <CoreFunction, PType>();
            argTypes         = new Dictionary <CoreFunction, PType[]>();
            argTypesRepeated = new Dictionary <CoreFunction, bool[]>();

            string[] rows = GetCoreFunctionSignatureManifest().Split('\n');
            foreach (string row in rows)
            {
                string definition = row.Trim();
                if (definition.Length > 0)
                {
                    TokenStream tokens     = new TokenStream(Tokenizer.Tokenize("core function manifest", row));
                    PType       returnType = PType.Parse(tokens);
                    string      name       = tokens.Pop().Value;
                    tokens.PopExpected("(");
                    List <PType> argList     = new List <PType>();
                    List <bool>  argRepeated = new List <bool>();
                    while (!tokens.PopIfPresent(")"))
                    {
                        if (argList.Count > 0)
                        {
                            tokens.PopExpected(",");
                        }
                        argList.Add(PType.Parse(tokens));
                        if (tokens.PopIfPresent("."))
                        {
                            argRepeated.Add(true);
                            tokens.PopExpected(".");
                            tokens.PopExpected(".");
                        }
                        else
                        {
                            argRepeated.Add(false);
                        }
                    }

                    if (tokens.HasMore)
                    {
                        throw new Exception("Invalid entry in the manifest. Stuff at the end: " + row);
                    }

                    CoreFunction func = lookup[name];
                    returnTypes[func]      = returnType;
                    argTypes[func]         = argList.ToArray();
                    argTypesRepeated[func] = argRepeated.ToArray();
                }
            }
        }
Example #6
0
        /// <summary>All messages for the SecurityOverlord come through this loop.
        /// It demuxes between Security, SecureData, and SecureControl packets, while
        /// the remaining packets are left to the default handler.</summary>
        override public void HandleData(MemBlock data, ISender return_path, object state)
        {
            MemBlock payload = null;
            PType    t       = null;

            try {
                t = PType.Parse(data, out payload);

                if (t.Equals(Security))
                {
                    HandleData(payload, return_path, null);
                }
                else if (t.Equals(SecureData))
                {
                    HandleData(payload, return_path);
                }
                else if (t.Equals(SecureControl))
                {
                    HandleControl(payload, return_path);
                }
                else if (t.Equals(PType.Protocol.ReqRep))
                {
                    _rrman.HandleData(payload, return_path, null);
                }
                else
                {
                    Edge edge = return_path as Edge;
                    if (edge != null && !(edge is Brunet.Security.Transport.SecureEdge))
                    {
                        throw new Exception("Insecure edge attempting to communicate with the node!");
                    }
                    Subscriber sub = _sub;
                    if (sub == null)
                    {
                        throw new Exception("No default handler... this won't do!");
                    }
                    _sub.Handle(data, return_path);
                }
            } catch (Exception e) {
                string ps = string.Empty;
                try {
                    ps = payload.GetString(System.Text.Encoding.ASCII);
                } catch { }
                ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format(
                                        "Security Packet Handling Exception, Type: {0}, From: {1}\n\tData: {2}\n\tException:{3}\n\tStack Trace:{4}",
                                        t, return_path, ps, e, new System.Diagnostics.StackTrace(true)));
            }
        }
Example #7
0
        /**
         * When a packet is to be delivered to this node,
         * this method is called.  This method is public so that
         * we can chain protocols through the node.  For instance,
         * after a packet is handled, it may be a wrapped packet
         * which actually contains another packet inside.  Thus,
         * the unwrapped packet could be "Announced" by the handler
         *
         * One needs to be careful to prevent an infinite loop of
         * a Handler announcing the packet it is supposed to handle.
         */
        protected virtual void Announce(MemBlock b, ISender from)
        {
            //When Subscribe or unsubscribe are called,
            //they make copies of the ArrayList, thus we
            //only need to hold the sync while we are
            //getting the list of handlers.

            /*
             * Note that getting from Hashtable is threadsafe, multiple
             * threads writing is a problem
             */
            MemBlock    payload  = null;
            int         handlers = 0;
            MultiSource ns       = null;
            PType       t        = null;

            try {
                t        = PType.Parse(b, out payload);
                ns       = (MultiSource)DemuxHandler.GetTypeSource(t);
                handlers = ns.Announce(payload, from);

                /**
                 * @todo if no one handled the packet, we might want to send some
                 * ICMP-like message.
                 */
                if (handlers == 0)
                {
                    string p_s = payload.GetString(System.Text.Encoding.ASCII);
                    ProtocolLog.WriteIf(ProtocolLog.Exceptions, String.Format(
                                            "No Handler for packet type: {0} from: {2}\n{1} :: {3}", t, p_s, from, b.ToBase16String()));
                }
            }
            catch (Exception x) {
                ProtocolLog.WriteIf(ProtocolLog.Exceptions, String.Format(
                                        "Packet Handling Exception"));
                string nodeSource = "null";
                if (ns != null)
                {
                    nodeSource = ns.ToString();
                }
                ProtocolLog.WriteIf(ProtocolLog.Exceptions, String.Format(
                                        "Handler: {0}\tEdge: {1}", nodeSource, from));
                ProtocolLog.WriteIf(ProtocolLog.Exceptions, String.Format(
                                        "Exception: {0}", x));
            }
        }
Example #8
0
        protected void HandleReply(ReqrepType rt, int idnum, MemBlock rest, ISender ret_path)
        {
            RequestState reqs;

            if (_req_state_table.TryGet(idnum, out reqs))
            {
                IReplyHandler handler = null;
                lock ( _sync ) {
                    if (reqs.AddReplier(ret_path))
                    {
                        TimeSpan rtt = DateTime.UtcNow - reqs.ReqDate;
                        _to_mgr.AddReplySampleFor(reqs, ret_path, rtt);
                        handler = reqs.ReplyHandler;
                    }
                }

                /*
                 * Now handle this reply
                 */
                if (null != handler)
                {
                    MemBlock   payload;
                    PType      pt         = PType.Parse(rest, out payload);
                    Statistics statistics = new Statistics();
                    statistics.SendCount = reqs.SendCount;
  #if REQREP_DEBUG
                    Console.Error.WriteLine("[ReqrepManager: {0}] Receiving reply on request id: {1}, from: {2}",
                                            _info, idnum, ret_path);
  #endif

                    //Don't hold the lock while calling the ReplyHandler:
                    bool continue_listening = handler.HandleReply(this, rt, idnum, pt, payload,
                                                                  ret_path, statistics, reqs.UserState);
                    //the request has been served
                    if (!continue_listening)
                    {
                        StopRequest(idnum, handler);
                    }
                }
            }
            else
            {
                //We are ignoring this reply, it either makes no sense, or we have
                //already handled it
            }
        }
Example #9
0
        public static List <ExtensibleFunction> Parse(string filename, string metadataFileContents)
        {
            List <ExtensibleFunction> output = new List <ExtensibleFunction>();

            Dictionary <string, PType>   returnTypeInfoForExtensibleMethods   = new Dictionary <string, PType>();
            Dictionary <string, PType[]> argumentTypeInfoForExtensibleMethods = new Dictionary <string, PType[]>();

            TokenStream tokens = new TokenStream(Tokenizer.Tokenize(filename, metadataFileContents));

            while (tokens.HasMore)
            {
                PType  returnType   = PType.Parse(tokens);
                string functionName = VerifyNameValid(tokens.Pop());
                tokens.PopExpected("(");
                List <PType> argTypes = new List <PType>();
                while (!tokens.PopIfPresent(")"))
                {
                    if (argTypes.Count > 0)
                    {
                        tokens.PopExpected(",");
                    }
                    argTypes.Add(PType.Parse(tokens));

                    // This is unused but could be later used as part of an auto-generated documentation for third-party platform implements of existing libraries.
                    string argumentName = VerifyNameValid(tokens.Pop());
                }
                tokens.PopExpected(";");

                returnTypeInfoForExtensibleMethods[functionName]   = returnType;
                argumentTypeInfoForExtensibleMethods[functionName] = argTypes.ToArray();
            }

            foreach (string functionName in returnTypeInfoForExtensibleMethods.Keys)
            {
                output.Add(new ExtensibleFunction()
                {
                    Name       = functionName,
                    ReturnType = returnTypeInfoForExtensibleMethods[functionName],
                    ArgTypes   = argumentTypeInfoForExtensibleMethods[functionName],
                });
            }

            return(output);
        }
Example #10
0
        public void HandleData(MemBlock b, ISender from, object state)
        {
            MemBlock payload = null;
            PType    t       = null;

            try {
                t = PType.Parse(b, out payload);
                if (t.Equals(PType.Protocol.ReqRep))
                {
                    _rrm.HandleData(payload, from, state);
                }
                else if (t.Equals(PType.Protocol.Rpc))
                {
                    Rpc.HandleData(payload, from, state);
                }
            }
            catch (Exception x) {
                Console.Error.WriteLine("Packet Handling Exception: {3}\n\tType: {0}\n\t\n\tFrom: {1}\n\tData: {2}",
                                        t, from, payload.GetString(System.Text.Encoding.ASCII), x);
            }
        }
Example #11
0
        public virtual void Send(ICopyable data)
        {
            if (_rand.NextDouble() < _drop_rate)
            {
                return;
            }

            MemBlock mdata = data as MemBlock;

            if (mdata == null)
            {
                mdata = MemBlock.Copy(data);
            }

            for (int i = 0; i < _remove_n_ptypes; i++)
            {
                MemBlock payload = mdata;
                PType.Parse(mdata, out payload);
                mdata = payload;
            }
            Receiver.HandleData(mdata, ReturnPath, State);
        }
Example #12
0
        public FunctionDefinition ParseFunctionDefinition(TokenStream tokens)
        {
            PType returnType = PType.Parse(tokens);
            Token nameToken  = EnsureTokenIsValidName(tokens.Pop(), "Expected function name");

            tokens.PopExpected("(");
            List <PType> argTypes = new List <PType>();
            List <Token> argNames = new List <Token>();

            while (!tokens.PopIfPresent(")"))
            {
                if (argTypes.Count > 0)
                {
                    tokens.PopExpected(",");
                }
                argTypes.Add(PType.Parse(tokens));
                argNames.Add(EnsureTokenIsValidName(tokens.Pop(), "Invalid function arg name"));
            }
            List <Executable> code = this.ParseCodeBlock(tokens, true);

            return(new FunctionDefinition(nameToken, returnType, argTypes, argNames, code));
        }
Example #13
0
        protected void HandleReply(ReqrepType rt, int idnum, MemBlock rest, ISender ret_path)
        {
            RequestState reqs;

            if (_req_state_table.TryGet(idnum, out reqs))
            {
                IReplyHandler handler = null;
                lock ( _sync ) {
                    if (reqs.AddReplier(ret_path))
                    {
                        TimeSpan rtt = DateTime.UtcNow - reqs.ReqDate;

                        /*
                         * Let's look at how long it took to get this reply:
                         */
                        if (reqs.GotAck)
                        {
                            //Use more standard deviations for acked messages.  We
                            //just don't want to let it run forever.
                            _acked_reqtimeout = ComputeNewTimeOut(rtt.TotalMilliseconds,
                                                                  _acked_rtt_stats,
                                                                  _MINIMUM_TIMEOUT, 3 * _STD_DEVS);
                        }
                        else if (ret_path is Edge)
                        {
                            _edge_reqtimeout = ComputeNewTimeOut(rtt.TotalMilliseconds,
                                                                 _edge_rtt_stats,
                                                                 _MINIMUM_TIMEOUT, _STD_DEVS);
                        }
                        else
                        {
                            _nonedge_reqtimeout = ComputeNewTimeOut(rtt.TotalMilliseconds,
                                                                    _nonedge_rtt_stats, _MINIMUM_TIMEOUT, _STD_DEVS);
                        }
                        handler = reqs.ReplyHandler;
                    }
                }

                /*
                 * Now handle this reply
                 */
                if (null != handler)
                {
                    MemBlock   payload;
                    PType      pt         = PType.Parse(rest, out payload);
                    Statistics statistics = new Statistics();
                    statistics.SendCount = reqs.SendCount;
  #if REQREP_DEBUG
                    Console.Error.WriteLine("[ReqrepManager: {0}] Receiving reply on request id: {1}, from: {2}",
                                            _info, idnum, ret_path);
  #endif

                    //Don't hold the lock while calling the ReplyHandler:
                    bool continue_listening = handler.HandleReply(this, rt, idnum, pt, payload,
                                                                  ret_path, statistics, reqs.UserState);
                    //the request has been served
                    if (!continue_listening)
                    {
                        StopRequest(idnum, handler);
                    }
                }
            }
            else
            {
                //We are ignoring this reply, it either makes no sense, or we have
                //already handled it
            }
        }
Example #14
0
        public ClassDefinition ParseClassDefinition(TokenStream tokens)
        {
            Token           classToken    = tokens.PopExpected("class");
            Token           nameToken     = tokens.PopIdentifier();
            ClassDefinition cd            = new ClassDefinition(this.context, classToken, nameToken);
            List <Token>    inheritTokens = new List <Token>();

            if (tokens.PopIfPresent(":"))
            {
                while (!tokens.IsNext("{"))
                {
                    if (inheritTokens.Count > 0)
                    {
                        tokens.PopExpected(",");
                    }
                    inheritTokens.Add(tokens.PopIdentifier());
                }
            }
            cd.InheritTokens = inheritTokens.ToArray();
            tokens.PopExpected("{");

            Dictionary <string, ICompilationEntity> members = new Dictionary <string, ICompilationEntity>();

            while (!tokens.PopIfPresent("}"))
            {
                string next = tokens.PeekValue();
                if (next == "constructor")
                {
                    if (cd.Constructor != null)
                    {
                        throw new ParserException(tokens.Peek(), "Only one constructor is permitted per class.");
                    }

                    Token constructorToken = tokens.PopExpected("constructor");
                    tokens.PopExpected("(");
                    List <PType> argTypes = new List <PType>();
                    List <Token> argNames = new List <Token>();
                    while (!tokens.PopIfPresent(")"))
                    {
                        if (argTypes.Count > 0)
                        {
                            tokens.PopExpected(",");
                        }
                        argTypes.Add(PType.Parse(tokens));
                        argNames.Add(tokens.PopIdentifier());
                    }
                    cd.Constructor        = new ConstructorDefinition(this.context, constructorToken, argTypes, argNames, cd);
                    this.currentCodeOwner = cd.Constructor;
                    cd.Constructor.Code   = this.ParseCodeBlock(tokens, true).ToArray();
                }
                else
                {
                    ICompilationEntity entity;
                    string             entityName;
                    PType memberType = PType.TryParse(tokens);
                    Token memberName = tokens.PopIdentifier();
                    bool  isMethod   = tokens.IsNext("(");
                    if (isMethod)
                    {
                        tokens.PopExpected("(");
                        List <PType> argTypes = new List <PType>();
                        List <Token> argNames = new List <Token>();
                        while (!tokens.PopIfPresent(")"))
                        {
                            if (argTypes.Count > 0)
                            {
                                tokens.PopExpected(",");
                            }
                            argTypes.Add(PType.Parse(tokens));
                            argNames.Add(tokens.PopIdentifier());
                        }
                        FunctionDefinition fd = new FunctionDefinition(memberName, memberType, argTypes, argNames, this.context, cd);
                        this.currentCodeOwner = fd;
                        List <Executable> code = this.ParseCodeBlock(tokens, true);
                        fd.Code    = code.ToArray();
                        entity     = fd;
                        entityName = fd.Name;
                    }
                    else
                    {
                        FieldDefinition fd = new FieldDefinition(this.context, memberType, memberName, cd);
                        this.currentCodeOwner = fd;
                        Expression initialValue = null;
                        if (tokens.PopIfPresent("="))
                        {
                            initialValue = this.ParseExpression(tokens);
                        }
                        else
                        {
                            if (memberType.IsNullable)
                            {
                                initialValue = new InlineConstant(memberType, memberName, null, cd);
                            }
                            else
                            {
                                switch (memberType.RootValue)
                                {
                                case "double": initialValue = new InlineConstant(memberType, memberName, 0.0, cd); break;

                                case "int": initialValue = new InlineConstant(memberType, memberName, 0, cd); break;

                                case "string": initialValue = new InlineConstant(memberType, memberName, null, cd); break;

                                default: throw new NotImplementedException();
                                }
                            }
                        }
                        tokens.PopExpected(";");
                        fd.Value   = initialValue;
                        entity     = fd;
                        entityName = fd.NameToken.Value;
                    }

                    if (members.ContainsKey(entityName))
                    {
                        throw new ParserException(memberName,
                                                  "There are conflicting members in the class '" + cd.NameToken.Value + "' for the name '" + entityName + "'.");
                    }

                    members[entityName] = entity;
                }
            }

            cd.AddMembers(members);

            return(cd);
        }
Example #15
0
        /** Handle incoming data on an Edge
         */
        public void HandleData(MemBlock data, ISender retpath, object state)
        {
            MemBlock rest_of_data;
            PType    p;

            if (state == null)
            {
                try {
                    p = PType.Parse(data, out rest_of_data);
                } catch (ParseException) {
                    ProtocolLog.WriteIf(ProtocolLog.Pathing, "Invalid PType from: " + data);
                    return;
                }
                p = PType.Parse(data, out rest_of_data);
            }
            else
            {
                //a demux has already happened:
                p            = (PType)state;
                rest_of_data = data;
            }

            if (PType.Protocol.Pathing.Equals(p))
            {
                /*
                 * We use a special PType to denote this transaction so
                 * we don't confuse it with other RepRep communication
                 */
                _rrm.HandleData(rest_of_data, retpath, null);
            }
            else if (PType.Protocol.Rpc.Equals(p))
            {
                /*
                 * Send this to the RpcHandler
                 */
                Rpc.HandleData(rest_of_data, retpath, null);
            }
            else
            {
                /*
                 * This is some other data
                 * It is either:
                 * 1) Time to announce an already created edge.
                 * 2) Assume this is a "default path" edge creation, to be backwards
                 * compatible
                 */
                Edge     e  = null;
                PathEdge pe = null;
                try {
                    e = (Edge)retpath;
                    PathEdgeListener pel = null;
                    lock ( _sync ) {
                        if (_unannounced.TryGetValue(e, out pe))
                        {
                            //
                            _unannounced.Remove(e);
                            pel = _pel_map[pe.LocalPath];
                        }
                    }
                    if (pe == null)
                    {
                        if (!_pel_map.ContainsKey(Root))
                        {
                            ProtocolLog.WriteIf(ProtocolLog.Pathing, "No root, can't create edge");
                            if (e != null)
                            {
                                e.Close();
                            }
                            return;
                        }

                        /*
                         * This must be a "default path" incoming connection
                         */
                        pel = _pel_map[Root];
                        pe  = new PathEdge(this, e, Root, Root);
                    }
                    pel.SendPathEdgeEvent(pe);
                    pe.Subscribe();
                    pe.ReceivedPacketEvent(data);
                }
                catch (Exception x) {
                    if (pe != null)
                    {
                        //This closes both edges:
                        pe.Close();
                    }
                    else if (e != null)
                    {
                        ProtocolLog.WriteIf(ProtocolLog.Pathing,
                                            String.Format("Closing ({0}) due to: {1}", e, x));
                        e.Close();
                    }
                }
            }
        }
Example #16
0
        public Executable ParseExecutable(TokenStream tokens, bool isForLoop)
        {
            if (!isForLoop)
            {
                switch (tokens.PeekValue())
                {
                case "if": return(ParseIfStatement(tokens));

                case "for": return(ParseForLoop(tokens));

                case "while": return(ParseWhileLoop(tokens));

                case "switch": return(ParseSwitchStatement(tokens));

                case "break": return(ParseBreak(tokens));

                case "return": return(ParseReturn(tokens));
                }
            }

            string token1 = tokens.PeekAhead(0);
            string token2 = tokens.PeekAhead(1);
            string token3 = tokens.PeekAhead(2);

            string DEBUG_HELP = (token1 + " " + (token2 ?? "") + " " + (token3 ?? "")).Trim();

            if (DEBUG_HELP == "set me to stuff")
            {
            }

            if (
                (token2 == "<" && IsValidName(token1) && IsValidName(token3)) || // Type<G1, G2> var = ...
                (token3 == "=" && IsValidName(token1) && IsValidName(token2)) || // Type var = ...
                (token2 == "[" && token3 == "]" && IsValidName(token1)) ||       // Type[] ...
                (token3 == ";" && IsValidName(token1) && IsValidName(token2)))   // Type var;
            {
                PType type         = PType.Parse(tokens);
                Token variableName = EnsureTokenIsValidName(tokens.Pop(), "Invalid variable name");

                if (tokens.PopIfPresent(";"))
                {
                    return(new VariableDeclaration(type, variableName, null, null));
                }

                Token      equalsToken     = tokens.PopExpected("=");
                Expression assignmentValue = ParseExpression(tokens);
                if (!isForLoop)
                {
                    tokens.PopExpected(";");
                }
                return(new VariableDeclaration(type, variableName, equalsToken, assignmentValue));
            }

            Expression expression = ParseExpression(tokens);

            if (!isForLoop && tokens.PopIfPresent(";"))
            {
                return(new ExpressionAsExecutable(expression));
            }

            if (isForLoop && (tokens.IsNext(";") || tokens.IsNext(",") || tokens.IsNext(")")))
            {
                return(new ExpressionAsExecutable(expression));
            }

            if (OP_TOKENS.Contains(tokens.PeekValue()))
            {
                Token      opToken         = tokens.Pop();
                Expression assignmentValue = ParseExpression(tokens);

                if (!isForLoop && tokens.PopIfPresent(";"))
                {
                    return(new Assignment(expression, opToken, assignmentValue));
                }

                if (isForLoop && (tokens.IsNext(";") || tokens.IsNext(",") || tokens.IsNext(")")))
                {
                    return(new Assignment(expression, opToken, assignmentValue));
                }
            }

            tokens.PopExpected(";"); // Exhausted possibilities. This will crash intentionally.
            return(null);            // unreachable code
        }