Esempio n. 1
0
        /*
         *
         *  GetAst
         *
         *  functor to decouple the intricacies of translation and scoping ( particularly scoping and choice of grammar start production )
         *  to be moved elswhere later
         *
         *  passing in an already generated AST does not make sense because this only this part is supposed to know how to react to errors ( how pass them on to the interactive shell and so forth )
         */



        public static ShellCommon.AC_Resp AC(ShellCommon.AC_Req shell_ac_request,
                                             Func <IEnumerable <PTokBase>, NamedNode> GetAst  // Shell needs to do its own tokenization
                                             )
        {
            var    RESPONDER  = new Responder(shell_ac_request);
            string str_in     = shell_ac_request.arg;
            int    cursor_pos = shell_ac_request.offs;

            /*
             *  atm error tokens are normal PTok's with E == PTokE.ErrT
             *  no special treatment in stripping needed - there are simply no productions that recognize token sequences with ErrT's among them
             */
            var l_toks = Lexer.Tokenize(str_in, relaxed: true);

            var TokL = new TokLinePlanB <PTok>();

            foreach (PTokBase tb in l_toks)
            {
                if (tb is PTok)
                {
                    TokL.AddTok((PTok)tb);
                }
                else
                {
                    TokL.AddWS((tb as PTokWhitespace).len);
                }
            }


            var CPos = TokL.CPosFromStringpos(cursor_pos);

            PTok AC_Tok = CPos.conflated_clusterF_AC_tok();

            if (AC_Tok == null)
            {
                return(RESPONDER.NoAC(" no acable tok ").ac_response);
            }
            NamedNode AST;

            try {
                AST = GetAst(l_toks);
            } catch (Exception e) {
                return(RESPONDER.NoAC(e.ToString()).ac_response);         // <-- this uses includes variable resolution and all kinds of other shenanigans, that are only needed for membAC, typeAC is a lot simpler - could do with only parsing
            }
            if (AST == null)
            {
                return(RESPONDER.NoAC(" GetAst() == null  ").ac_response);
            }



            // with epsilon consuming productions ( ex: DeclStar ) "all Leafs are TermNodes" can not be relied on anymore
            var TermLeafs = AST.Leafs().Where(nn => nn is MG.TermNode).Select(n => (MG.TermNode)n).ToArray().NLSendRec("term leafs");

            NamedNode AC_Node = null;
            int       i       = 0;

            for (; i < TermLeafs.Length; i++)
            {
                if (TermLeafs[i].tok == AC_Tok)
                {
                    AC_Node = TermLeafs[i]; break;
                }
            }

            if (AC_Node == null)
            {
                return(RESPONDER.NoAC("ac beyond parsable").ac_response);                    // TODO :  D.Assert() that this is actually true with something like :  PToks.Skip(i).Where( term.tok == AC_Tok).Single
            }
            NamedNode descrNode = AC_Node.PathUpTo((n) => (n is MG.ACable));

            if (descrNode == null)
            {
                return(RESPONDER.NoAC(" descrNode == null  ").ac_response);
            }


            if (descrNode is MG.ACableMemb)
            {
                return(MembAcc_AC(TokL, CPos, (MGRX.MemANodeRX)descrNode, RESPONDER).ac_response);                                                   // <- todo cast not typesafe
            }
            else if (descrNode is MG.ACableTypeName)
            {
                return(Type_AC(TokL, CPos, descrNode, RESPONDER).ac_response);
            }
            else if (descrNode is MG.ACableFuncName)
            {
                return(FuncName_AC(TokL, CPos, (MGRX.FuncNameNodeRX)descrNode, RESPONDER).ac_response);
            }
            else
            {
                throw new NotImplementedException();
            }
        }
Esempio n. 2
0
        public static FinalizedResponse Type_AC(TokLinePlanB <PTok> orig_TL, TokLinePlanB <PTok> .CPosC CPos, NamedNode n, Responder RESP)
        {
            Func <PTokE, bool> ON = tokE => { var tok = CPos.insideof_tok;            if (tok == null)
                                              {
                                                  return(false);
                                              }
                                              return(tok.E == tokE); };
            Func <PTokE, bool> AFTER = tokE => { var tok = CPos.immediateLAdj_tok; if (tok == null)
                                                 {
                                                     return(false);
                                                 }
                                                 return(tok.E == tokE); };

            MGRX.TypeNameNodeRX TNRX_node = (MGRX.TypeNameNodeRX)n;

            if (ON(PTokE.CS_name) || AFTER(PTokE.CS_name))
            {
                PTok targetTok = null;
                if ((CPos.insideof_tok != null) && (CPos.insideof_tok.E == PTokE.CS_name))
                {
                    targetTok = CPos.insideof_tok;
                }
                else
                {
                    targetTok = CPos.immediateLAdj_tok;   // todo: unsafe
                }
                var Largs = new List <string>();
                foreach (var tok in TNRX_node.nameToks)
                {
                    Largs.Add(tok.pay); if (tok == targetTok)
                    {
                        break;
                    }
                }                                                                                                  // targetTok might not be the last in sequence - collect all CS_names upto and including

                string prefix    = null;
                var    type_alts = SGA.QTN_AC(Largs.ToArray(), out prefix);

                if (prefix.Length > targetTok.pay.Length)
                {
                    var new_tok = new PTok {
                        E = PTokE.CS_name, pay = prefix
                    };
                    orig_TL.ReplaceTok(targetTok, new_tok);
                    return(RESP.TypeACWithSubst(type_alts, SerializeTokLine(orig_TL), orig_TL.CPosAtEndOfTok(new_tok).StringPos()));
                }
                else
                {
                    return(RESP.TypeACNoSubst(type_alts));
                }
            }
            else if (CPos.immediateLAdj_tok == null)        // abuse this as "on whitespace or EOL" - probably incomplete
            // problem :
            // TokLine was not designed with the possibility in mind that Tokens change without notice
            // thus: insert dummy token | do stuff | replace dummy token with the final one

            {
                PTok placeholderTok = new PTok {
                    E = PTokE.CS_name, pay = ""
                };
                var placeholderCpos = orig_TL.InsertAfterCPos(CPos, placeholderTok);

                // extra evil - accessing internal Node structure directly - wo way to iterate from CPosC yet
                PTok delim = null;  // non whitespace token to the left of insertion point
                var  cand  = placeholderCpos.N.left;
                while (true)
                {
                    if (cand is TokLinePlanB <PTok> .NodeTok)
                    {
                        delim = cand.tok; break;
                    }
                    cand = cand.left;
                }

                var Largs = new List <string>();
                foreach (var tok in TNRX_node.Leafs().Where(N => N is MG.TermNode).Select(MG.TermTok))        // have to iterate over all terminals instead of just CS_names , because delimiter might be some other kind
                {
                    if (tok.E == PTokE.CS_name)
                    {
                        Largs.Add(tok.pay);
                    }
                    if (tok == delim)
                    {
                        break;                  // collect inclusive delimiter
                    }
                }
                Largs.Add(""); // last arg to SuggTree is an empty prefix
                string prefix;
                var    alts = SGA.QTN_AC(Largs.ToArray(), out prefix);
                if (prefix.Length > 0)
                {
                    return(RESP.TypeACNoSubst(alts));
                }
                else
                {
                    var final_tok = new PTok {
                        E = PTokE.CS_name, pay = prefix
                    };
                    orig_TL.ReplaceTok(placeholderTok, final_tok);
                    return(RESP.TypeACWithSubst(alts, SerializeTokLine(orig_TL), orig_TL.CPosAtEndOfTok(final_tok).StringPos()));
                }
            }



            return(RESP.NoAC("kind of type AC not implemented atm"));
        }
Esempio n. 3
0
        public static FinalizedResponse FuncName_AC(TokLinePlanB <PTok> orig_TL, TokLinePlanB <PTok> .CPosC CPos, MGRX.FuncNameNodeRX funcNameNodeRX, Responder RESP)
        {
            Func <PTokE, bool> ON = tokE => { var tok = CPos.insideof_tok;            if (tok == null)
                                              {
                                                  return(false);
                                              }
                                              return(tok.E == tokE); };
            Func <PTokE, bool> LADJ = tokE => { var tok = CPos.immediateLAdj_tok;       if (tok == null)
                                                {
                                                    return(false);
                                                }
                                                return(tok.E == tokE); };

            Func <TokLinePlanB <PTok>, PTokBase[]> SER = tokLine => tokLine.Serialize <PTokBase>(onTok: _ => _, onWS: i => new PTokWhitespace {
                len = i
            }).ToArray();

            Type hosting_type;

            try {
                hosting_type = funcNameNodeRX.AC_FuncHostingType_Callback();
                if (hosting_type == null)
                {
                    throw new Exception("hosting type null");
                }
            } catch (Exception e) {
                return(RESP.NoAC(e.Message));
            }
            string name_fragment;

            if (LADJ(PTokE.CS_name))
            {
                name_fragment = CPos.immediateLAdj_tok.pay;

                MethodInfo [] raw_suggs_MI = SGA.MethodAC(hosting_type, name_fragment, (funcNameNodeRX.parent as MG.FunCallNode).isStatic);
                if (raw_suggs_MI.Length == 0)
                {
                    return(RESP.NoAC("no matching alternatives"));
                }

                string new_prefix = SGA.LongestCommonPrefix(raw_suggs_MI.Select(mi => mi.Name).ToArray());

                if (new_prefix.Length > name_fragment.Length)
                {
                    PTok new_token = new PTok {
                        pay = new_prefix, E = PTokE.CS_name
                    };
                    orig_TL.ReplaceTok(CPos.immediateLAdj_tok, new_token);

                    var nu_Cpos = orig_TL.CPosAtEndOfTok(new_token);
                    return(RESP.FuncACWithSubst(raw_suggs_MI, SER(orig_TL), nu_Cpos.StringPos()));
                }
                else
                {
                    return(RESP.FuncACNoSubst(raw_suggs_MI));
                }
            }
            else if (LADJ(PTokE.OP_backslash))
            {
                //  no check for whether the curser is under a CS_name token , like so
                //  [>> [_] :Tyname\Funcname]
                //              _
                // in this case junk gets substituted left of `Funcname`
                // idc rn - there are bigger fish to fry
                MethodInfo [] raw_suggs_MI = SGA.MethodAC(hosting_type, "", (funcNameNodeRX.parent as MG.FunCallNode).isStatic);
                if (raw_suggs_MI.Length == 0)
                {
                    return(RESP.NoAC("no matching alternatives"));
                }

                string new_prefix = SGA.LongestCommonPrefix(raw_suggs_MI.Select(mi => mi.Name).ToArray());
                if (new_prefix.Length > 0)
                {
                    var nu_tok = new PTok {
                        E = PTokE.CS_name, pay = new_prefix
                    };
                    orig_TL.InsertTokAfterNode(CPos.N, nu_tok);                    // this is the precise behaviour of IsertAfterCPos when its not over whitespace

                    var nu_Cpos = orig_TL.CPosAtEndOfTok(nu_tok);
                    var nu_offs = nu_Cpos.StringPos();

                    return(RESP.FuncACWithSubst(raw_suggs_MI, SER(orig_TL), nu_offs));
                }
                else
                {
                    return(RESP.FuncACNoSubst(raw_suggs_MI));
                }
            }
            else
            {
                return(RESP.NoAC("useless position"));
            }


            // currrently only doing ON( CS_name )
        }
Esempio n. 4
0
        public static FinalizedResponse MembAcc_AC(TokLinePlanB <PTok> orig_TL, TokLinePlanB <PTok> .CPosC pos, MGRX.MemANodeRX MA_node, Responder RESP)
        {
            #region setup

            string orig_prefix = MA_node.name;                                   // <- .name is normalized to "" , never null
            MembK  orig_MembK  = MembKF_from_refineTok(MA_node.refineOPTok);     // resolves to "_any" for null argument


            MemberInfo[] mis      = new MemberInfo[0];
            Type         baseType = null;
            try {
                // i *THINK* ACMembTypingCallback is supposed to be set at creation time of the corresponding TranslationUnit ( i.e. its constructor)  - this is not happening atm
                // fetch the type here to base SuggTreeFetching of MethodInfos on, the MembKFilter argument to that thing is something else entirely



                baseType = (MA_node as MG.ACableMemb).ACMembTypingCallback();
            } catch (MG.NoACPossible) {     // <- questionable if this exception is needed at all
                return(RESP.NoAC("excpt: MG.NoACPossible"));
            } catch (Exception e) {
                return(RESP.NoAC("general typing exception: " + e.ToString()));
            }
            if (baseType == null)
            {
                return(RESP.NoAC("baseType == null "));
            }

            try {
                mis = SGA.MembAC(baseType, orig_prefix, orig_MembK);
            } catch (Exception)  { return(RESP.NoAC(" SuggTree exception ")); }
            if (mis.Length == 0)
            {
                return(RESP.NoAC(" no suggs "));
            }


            #endregion

            string new_prefix = SGA.LongestCommonPrefix(mis.Select(mi => mi.Name).ToArray());

            bool insert_refinement = (MA_node.refineOPTok == null) && (mis.Length == 1);                    // current strat : only augment refinement op if suggestions are unique
            bool insert_name       = (MA_node.nameTok == null) /* && ( new_prefix.Length > 0 ) */;          // actually ... it's easier to always insert

            // --- if both refinement, and name are to be inserted: insert refinement first

            if (insert_refinement)
            {
                orig_TL.InsertTokAfterNode(
                    orig_TL.findTok(MA_node.initialOpTok),
                    refineTok_from_MembK(new MembK(mis[0]))      // implicitly assuming mis[] to be of length 1, or their MembKs to be identical in case of several
                    );
            }

            if (insert_name)
            {
                var new_nameTok = new PTok {
                    E = PTokE.CS_name, pay = new_prefix
                };
                pos = orig_TL.InsertAfterCPos(pos, new_nameTok);
            }
            else
            {
                // a nice invariant to fuzz against :  for all x ::   SG.MembAcc(x). map ( -> name ). LongestCommonPrefix().Length >= x.Length  ( this is implitily assumed here )
                // counter case : len ( longestCommonPrefix ) < len( MA_node.name ) should never reach this ( cuz mis == [] triggers return further up )
                D.Assert(new_prefix.Length >= orig_prefix.Length);
                MA_node.nameTok.pay = new_prefix;
                pos = orig_TL.CPosAtEndOfTok(MA_node.nameTok);
            }
            Func <MemberInfo, mi_sugg> conv_mi_sugg = (MI) => {
                var str_op = refineTok_from_MembK(new MembK(MI)).pay;
                return(new mi_sugg {
                    str_op = str_op,
                    mi = MI
                });
            };
            PTokBase [] nu_toks = orig_TL.Serialize <PTokBase>(onTok: _ => _, onWS: i => new PTokWhitespace {
                len = i
            }).ToArray();

            return(RESP.MembACWithSubst(mis.Select(conv_mi_sugg), nu_toks, pos.StringPos()));
        }