poke-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v3] repl: Enable auto-completion for structs


From: Carlo Caione
Subject: [PATCH v3] repl: Enable auto-completion for structs
Date: Mon, 17 Feb 2020 18:09:43 +0100

Enable auto-completion for struct fields when a TAB is pressed after a
'.' appended to the struct name (struct.<TAB>).

Signed-off-by: Carlo Caione <address@hidden>

        * src/pk-repl.c (pkl_complete_struct): new auto-complete function
        * src/pkl-ast.c (pkl_struct_type_traverse): new helper function
        * src/pkl-ast.h: likewise
---
 src/pk-repl.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/pkl-ast.c | 63 +++++++++++++++++++++++++++++++++++++++++++
 src/pkl-ast.h |  1 +
 3 files changed, 139 insertions(+)

diff --git a/src/pk-repl.c b/src/pk-repl.c
index 574b9935..ea9881d0 100644
--- a/src/pk-repl.c
+++ b/src/pk-repl.c
@@ -35,6 +35,77 @@
 #include <signal.h>
 #include <unistd.h>
 
+static char *
+pkl_complete_struct (int *idx, const char *x, size_t len, int state)
+{
+  static pkl_ast_node type;
+  pkl_ast_node t;
+  char *trunk;
+  int j;
+
+  if (state == 0)
+    {
+      pkl_env compiler_env;
+      int back, over;
+      char *base;
+
+      compiler_env = pkl_get_env (poke_compiler);
+      base = strndup (x, len - strlen (strchr (x, '.')));
+
+      type = pkl_env_lookup (compiler_env, base, &back, &over);
+      free (base);
+
+      if (type == NULL || PKL_AST_DECL_KIND (type) != PKL_AST_DECL_KIND_VAR)
+        return NULL;
+
+      type = PKL_AST_TYPE (PKL_AST_DECL_INITIAL (type));
+      type = pkl_struct_type_traverse (type, x);
+      if (type == NULL)
+        return NULL;
+    }
+
+  trunk = strndup (x, len - strlen (strrchr (x, '.')));
+  t = PKL_AST_TYPE_S_ELEMS (type);
+
+  for (j = 0; j < (*idx); j++)
+    t = PKL_AST_CHAIN (t);
+
+  for (; t; t = PKL_AST_CHAIN (t), (*idx)++)
+    {
+      pkl_ast_node ename;
+      char *field, *name;
+
+      if (PKL_AST_CODE (t) != PKL_AST_STRUCT_TYPE_FIELD)
+        continue;
+
+      ename = PKL_AST_STRUCT_TYPE_FIELD_NAME (t);
+
+      if (ename)
+          field = PKL_AST_IDENTIFIER_POINTER (ename);
+      else
+          field = "<unnamed field>";
+
+      name = xmalloc (strlen (trunk) + strlen (field) + 2);
+
+      strcpy (name, trunk);
+      strcat (name, ".");
+      strcat (name, field);
+
+      if (0 != strncmp (x, name, len))
+        {
+          free (name);
+          continue;
+        }
+
+      (*idx)++;
+      free (trunk);
+      return name;
+    }
+
+  free (trunk);
+  return NULL;
+}
+
 static char *
 poke_completion_function (const char *x, int state)
 {
@@ -55,6 +126,10 @@ poke_completion_function (const char *x, int state)
     }
 
   size_t len = strlen (x);
+
+  if ((x[0] != '.') && (strchr(x, '.') != NULL))
+    return pkl_complete_struct (&idx, x, len, state);
+
   char *function_name;
   function_name = pkl_env_get_next_matching_decl (env, &iter, x, len);
   if (function_name)
diff --git a/src/pkl-ast.c b/src/pkl-ast.c
index 0ae30563..9264fc30 100644
--- a/src/pkl-ast.c
+++ b/src/pkl-ast.c
@@ -621,6 +621,69 @@ pkl_ast_dup_type (pkl_ast_node type)
   return new;
 }
 
+/* Given a struct type node AST and a string in the form BB.CC.CC.xx,
+   check that the intermediate fields are valid struct references, and return
+   the pkl_ast_node corresponding to the type of the latest field CC. */
+
+pkl_ast_node
+pkl_struct_type_traverse (pkl_ast_node type, const char *path)
+{
+  char *trunk, *sub, *base;
+
+  if (PKL_AST_TYPE_CODE (type) != PKL_TYPE_STRUCT)
+    return NULL;
+
+  trunk = strndup (path, strlen (path) - strlen (strrchr (path, '.')));
+  base = strtok (trunk, ".");
+
+  /* Node in the form XX. Check to silence the compiler about base not used */
+  if (base == NULL)
+    {
+      free (trunk);
+      return type;
+    }
+
+  while ((sub = strtok (NULL, ".")) != NULL)
+    {
+      pkl_ast_node ename;
+      pkl_ast_node etype, t;
+      char *field;
+
+      etype = NULL;
+
+      if (PKL_AST_TYPE_CODE (type) != PKL_TYPE_STRUCT)
+        goto out;
+
+      for (t = PKL_AST_TYPE_S_ELEMS (type); t;
+           t = PKL_AST_CHAIN (t))
+        {
+          if (PKL_AST_CODE (t) != PKL_AST_STRUCT_TYPE_FIELD)
+            continue;
+      
+          ename = PKL_AST_STRUCT_TYPE_FIELD_NAME (t);
+          etype = PKL_AST_STRUCT_TYPE_FIELD_TYPE (t);
+
+          field = PKL_AST_IDENTIFIER_POINTER (ename);
+
+          if (STREQ (field, sub))
+            {
+              type = etype;
+              break;
+            }
+        }
+
+      if (type != etype)
+        goto out;
+    }
+
+  free (trunk);
+  return type;
+
+out:
+  free (trunk);
+  return NULL;
+}
+
 /* Return whether two given type AST nodes are equal, i.e. they denote
    the same type.  */
 
diff --git a/src/pkl-ast.h b/src/pkl-ast.h
index 114d6f14..5cab2814 100644
--- a/src/pkl-ast.h
+++ b/src/pkl-ast.h
@@ -930,6 +930,7 @@ void pkl_print_type (FILE *out, pkl_ast_node type, int 
use_given_name);
 char *pkl_type_str (pkl_ast_node type, int use_given_name);
 int pkl_ast_func_all_optargs (pkl_ast_node type);
 int pkl_ast_type_mappable_p (pkl_ast_node type);
+pkl_ast_node pkl_struct_type_traverse (pkl_ast_node type, const char *path);
 
 /* PKL_AST_DECL nodes represent the declaration of a named entity:
    function, type, variable....
-- 
2.20.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]