poke-devel
[Top][All Lists]
Advanced

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

[COMMITTED] pkl, testsuite, doc: defunit, support for arbitrary named un


From: Jose E. Marchesi
Subject: [COMMITTED] pkl, testsuite, doc: defunit, support for arbitrary named units
Date: Sat, 29 Feb 2020 14:39:06 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/26.1 (gnu/linux)

commit a1c28d8f416aa9cd6c1328b24b51178d1c900f9f
Author: Jose E. Marchesi <address@hidden>
Date:   Sat Feb 29 14:32:11 2020 +0100

    pkl,testsuite,doc: defunit, support for arbitrary named units
    
    This patch adds support for defunit, which is a language construction
    to define arbitrary named units:
    
    defunit KB = 1024 * 8;
    
    The named units live in their own namespace, and can be used in both
    offset literals and offset type specifiers.
    
    The standard library has been expanded to define the list of
    pre-defined units that were previously hardcoded in the compiler (b,
    B, Kb, etc.)
    
    Tests and documentation updates included.
    
    2020-02-29  Jose E. Marchesi  <address@hidden>
    
            * src/pkl-tab.y (DEFUNIT): New token.
            * src/pkl-lex.l (DEFUNIT): Likewise.
            * src/pk-cmd.c (pk_cmd_exec): Recognize defunit.
            * src/pkl-env.h (PKL_ENV_NS_MAIN): Define.
            (PKL_ENV_NS_UNITS): Likewise.
            * src/pkl-env.c (struct pkl_env): New field units_hash_table.
            (pkl_env_free): Handle units_hash_table.
            (pkl_env_dup_toplevel): Handle the units hash table.
            (pkl_env_lookup): Get a new argument `namespace'.
            (pkl_env_lookup_1): Likewise.
            (pkl_env_register): Likewise.
            (get_ns_table): New function.
            (pkl_env_lookup_1): Handle `namespace'.
            (struct pkl_env): New field num_units.
            * src/pkl-lex.l: Pass namespace to pkl_env_lookup.
            * src/pkl-tab.y: Likewise.
            * src/pk-def.c (print_var_decl): Likewise.
            * src/pk-repl.c (pkl_complete_struct): Likewise.
            * src/pk-vm.c (pk_cmd_vm_disas_fun): Likewise.
            (pk_cmd_vm_disas_fun): Likewise.
            * src/pkl-ast.h (PKL_AST_DECL_KIND_UNIT): Define.
            * src/pkl-ast.c (pkl_ast_id_to_offset_unit): Remove function.
            * src/pkl-anal.c (pkl_anal1_ps_decl): New handler.
            (pkl_phase_anal1): Install new handler.
            * src/pkl-typify.c (pkl_typify1_ps_decl): New handler.
            (pkl_phase_typify1): Install new handler.
            * src/pkl-trans.c (pkl_trans1_ps_offset): Do not handle
            identifiers in offset units.
            (pkl_trans1_ps_type_offset): Remove.
            (pkl_trans2_ps_offset_type): Fix error location.
            * src/pkl-fold.c (pkl_fold_ps_cast): Do not overwrite unit nodes
            while constant-folding offset casts.  Create a new node instead.
            * src/pkl-gen.c (pkl_gen_pr_decl): Handle PKL_AST_DECL_KIND_UNIT.
            * src/pkl-asm.c (pkl_asm_call): Pass a namespace to
            pkl_env_lookup.
            * src/std.pk (b,N,B,Kb,KB,Mb,MB,Gb,GB): Define units.
            * testsuite/poke.pkl/units-1.pk: New test.
            * testsuite/poke.pkl/units-2.pk: Likewise.
            * testsuite/poke.pkl/units-3.pk: Likewise.
            * testsuite/poke.pkl/units-4.pk: Likewise.
            * testsuite/poke.pkl/units-5.pk: Likewise.
            * testsuite/poke.pkl/units-6.pk: Likewise.
            * testsuite/poke.pkl/units-diag-1.pk: Likewise.
            * testsuite/poke.pkl/units-diag-2.pk: Likewise.
            * testsuite/poke.pkl/units-diag-3.pk: Likewise.
            * doc/poke.texi (Offset Units): New section.
            (Standard Units): New chapter.

diff --git a/ChangeLog b/ChangeLog
index b3190a8..3eaead2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,53 @@
+2020-02-29  Jose E. Marchesi  <address@hidden>
+
+       * src/pkl-tab.y (DEFUNIT): New token.
+       * src/pkl-lex.l (DEFUNIT): Likewise.
+       * src/pk-cmd.c (pk_cmd_exec): Recognize defunit.
+       * src/pkl-env.h (PKL_ENV_NS_MAIN): Define.
+       (PKL_ENV_NS_UNITS): Likewise.
+       * src/pkl-env.c (struct pkl_env): New field units_hash_table.
+       (pkl_env_free): Handle units_hash_table.
+       (pkl_env_dup_toplevel): Handle the units hash table.
+       (pkl_env_lookup): Get a new argument `namespace'.
+       (pkl_env_lookup_1): Likewise.
+       (pkl_env_register): Likewise.
+       (get_ns_table): New function.
+       (pkl_env_lookup_1): Handle `namespace'.
+       (struct pkl_env): New field num_units.
+       * src/pkl-lex.l: Pass namespace to pkl_env_lookup.
+       * src/pkl-tab.y: Likewise.
+       * src/pk-def.c (print_var_decl): Likewise.
+       * src/pk-repl.c (pkl_complete_struct): Likewise.
+       * src/pk-vm.c (pk_cmd_vm_disas_fun): Likewise.
+       (pk_cmd_vm_disas_fun): Likewise.
+       * src/pkl-ast.h (PKL_AST_DECL_KIND_UNIT): Define.
+       * src/pkl-ast.c (pkl_ast_id_to_offset_unit): Remove function.
+       * src/pkl-anal.c (pkl_anal1_ps_decl): New handler.
+       (pkl_phase_anal1): Install new handler.
+       * src/pkl-typify.c (pkl_typify1_ps_decl): New handler.
+       (pkl_phase_typify1): Install new handler.
+       * src/pkl-trans.c (pkl_trans1_ps_offset): Do not handle
+       identifiers in offset units.
+       (pkl_trans1_ps_type_offset): Remove.
+       (pkl_trans2_ps_offset_type): Fix error location.
+       * src/pkl-fold.c (pkl_fold_ps_cast): Do not overwrite unit nodes
+       while constant-folding offset casts.  Create a new node instead.
+       * src/pkl-gen.c (pkl_gen_pr_decl): Handle PKL_AST_DECL_KIND_UNIT.
+       * src/pkl-asm.c (pkl_asm_call): Pass a namespace to
+       pkl_env_lookup.
+       * src/std.pk (b,N,B,Kb,KB,Mb,MB,Gb,GB): Define units.
+       * testsuite/poke.pkl/units-1.pk: New test.
+       * testsuite/poke.pkl/units-2.pk: Likewise.
+       * testsuite/poke.pkl/units-3.pk: Likewise.
+       * testsuite/poke.pkl/units-4.pk: Likewise.
+       * testsuite/poke.pkl/units-5.pk: Likewise.
+       * testsuite/poke.pkl/units-6.pk: Likewise.
+       * testsuite/poke.pkl/units-diag-1.pk: Likewise.
+       * testsuite/poke.pkl/units-diag-2.pk: Likewise.
+       * testsuite/poke.pkl/units-diag-3.pk: Likewise.
+       * doc/poke.texi (Offset Units): New section.
+       (Standard Units): New chapter.
+
 2020-02-29  John Darrington <address@hidden>
 
        * src/pk-editor.c (pk_cmd_editor): Do nothing if poke is not running 
diff --git a/doc/poke.texi b/doc/poke.texi
index 54ba235..69548d0 100644
--- a/doc/poke.texi
+++ b/doc/poke.texi
@@ -111,6 +111,7 @@ Debugging Poke Programs
 The Standard Library
 * Standard Integral Types::    int, long and the like.
 * Standard Offset Types::      off64 and the like.
+* Standard Units::             b, B, Kb and the like.
 * Conversion Functions::       catos, atoi, etc.
 * String Functions::           Functions which deal with strings.
 * Sorting Functions::          qsort.
@@ -1391,6 +1392,7 @@ very central concept in poke.
 @menu
 * Why Offsets::                        Byte-oriented or bit-oriented?
 * Offset Literals::            Denoting offsets in Poke.
+* Offset Units::               Pears and potatoes.
 * Offset Types::               offset<...>.
 * Casting Offsets::            Converting offsets.
 * Offset Operations::          Operating with offsets.
@@ -1590,37 +1592,51 @@ denote ``a bytes'':
 a#B
 @end example
 
-In the offset syntax units are specified as @code{#@var{foo}}, where
-@var{FOO} is the name of the unit.  Poke provides the following list
-of hard coded unit names:
+In the offset syntax units are specified as @code{#@var{unit}}, where
+@var{unit} is the specification of an unit.  See the next section for
+details.
 
-@cindex units
+@node Offset Units
+@section Offset Units
 
-@table @code
-@item b
-bits.
-@item B
-bytes.
-@item Kb
-@cindex kilobits
-kilo bits (1024 bits.)
-@item KB
-@cindex kilobytes
-Kilo bytes (1024 bytes.)
-@item Mb
-@cindex megabits
-Mega bits.
-@item MB
-@cindex megabytes
-Mega bytes.
-@item Gb
-@cindex gigabits
-Giga bits.
-@end table
+There are several ways to express the unit of an offset, which is
+always interpreted as a multiple of the basic unit, which is the bit
+(one bit.)
 
-However, it is also possible to express units in multiples of the base
-unit, which is the bit.  Using this syntax, it becomes possible to
-express offsets in any arbitrary unit, as disparate as it may seem:
+@subsection Named Units
+
+The first way is to refer to an unit by name.  For example, @code{2#B}
+for two bytes.  Units are defined using the @code{defunit}
+construction:
+
+@example
+defunit @var{name} = @var{constant_expression};
+@end example
+
+Where @var{name} is the name of the unit, and
+@var{constant_expression} is a constant expression that should
+evaluate to an integral value.  The resulting value is always coerced
+into an unsigned 64-bit integer.
+
+Note that unit names live in a different namespace than variables and
+types.  However, when a given name is both a type name and an unit
+name in an unit context, the named unit takes precedence:
+
+@example
+(poke) deftype xx = int
+(poke) defunit xx = 2
+(poke) 1#xx
+1#2
+@end example
+
+Many useful units are defined in the standard library.  @xref{Standard
+Units}.
+
+@subsection Arbitrary Units
+
+It is also possible to express units in multiples of the base unit,
+which is the bit.  Using this syntax, it becomes possible to express
+offsets in any arbitrary unit, as disparate as it may seem:
 
 @example
 17#3
@@ -1632,6 +1648,8 @@ That's it, 17 units of 3 bits each, zero units of 12 bits 
each,
 and eight units of 1 bit each.  Note that the unit should be bigger
 than 0.
 
+@subsection Types as Units
+
 But then, why stopping there?  Poking is all about defining data
 structures and operating on them@dots{} so why not using these structures
 as units as well?  Consider the following struct:
@@ -4307,6 +4325,35 @@ types.
 64-bit unsigned offset in bits.
 @end table
 
+@node Standard Units
+@chapter Standard Units
+
+The following list of units are defined in the standard library.
+
+@cindex units
+
+@table @code
+@item b
+bits.
+@item B
+bytes.
+@item Kb
+@cindex kilobits
+kilo bits (1024 bits.)
+@item KB
+@cindex kilobytes
+Kilo bytes (1024 bytes.)
+@item Mb
+@cindex megabits
+Mega bits.
+@item MB
+@cindex megabytes
+Mega bytes.
+@item Gb
+@cindex gigabits
+Giga bits.
+@end table
+
 @node Conversion Functions
 @chapter Conversion Functions
 @cindex conversion functions
diff --git a/src/pk-cmd.c b/src/pk-cmd.c
index 3c07f9e..547674f 100644
--- a/src/pk-cmd.c
+++ b/src/pk-cmd.c
@@ -619,7 +619,9 @@ pk_cmd_exec (char *str)
           if (strncmp (ecmd, "defvar ", 6) == 0
               || strncmp (ecmd, "defvar\t", 6) == 0
               || strncmp (ecmd, "deftype ", 8) == 0
-              || strncmp (ecmd, "deftype\t", 8) == 0)
+              || strncmp (ecmd, "deftype\t", 8) == 0
+              || strncmp (ecmd, "defunit", 7) == 0
+              || strncmp (ecmd, "defunit\t", 8) == 0)
             what = 0;
           else
             what = 1;
diff --git a/src/pk-def.c b/src/pk-def.c
index 8e6bbe2..9325009 100644
--- a/src/pk-def.c
+++ b/src/pk-def.c
@@ -48,6 +48,7 @@ print_var_decl (pkl_ast_node decl, void *data)
     return;
 
   tmp = pkl_env_lookup (compiler_env,
+                        PKL_ENV_NS_MAIN,
                         PKL_AST_IDENTIFIER_POINTER (decl_name),
                         &back, &over);
   assert (tmp != NULL);
@@ -89,6 +90,7 @@ print_fun_decl (pkl_ast_node decl, void *data)
     return;
 
   tmp = pkl_env_lookup (compiler_env,
+                        PKL_ENV_NS_MAIN,
                         PKL_AST_IDENTIFIER_POINTER (decl_name),
                         &back, &over);
   assert (tmp != NULL);
diff --git a/src/pk-repl.c b/src/pk-repl.c
index 3af357b..3e7215a 100644
--- a/src/pk-repl.c
+++ b/src/pk-repl.c
@@ -55,7 +55,8 @@ pkl_complete_struct (int *idx, const char *x, size_t len, int 
state)
       compiler_env = pkl_get_env (poke_compiler);
       base = strndup (x, len - strlen (strchr (x, '.')));
 
-      type = pkl_env_lookup (compiler_env, base, &back, &over);
+      type = pkl_env_lookup (compiler_env, PKL_ENV_NS_MAIN,
+                             base, &back, &over);
       free (base);
 
       if (type == NULL || PKL_AST_DECL_KIND (type) != PKL_AST_DECL_KIND_VAR)
diff --git a/src/pk-vm.c b/src/pk-vm.c
index ee16a96..8a9dfb6 100644
--- a/src/pk-vm.c
+++ b/src/pk-vm.c
@@ -66,8 +66,8 @@ pk_cmd_vm_disas_fun (int argc, struct pk_cmd_arg argv[], 
uint64_t uflags)
 
   fname = PK_CMD_ARG_STR (argv[0]);
 
-  decl = pkl_env_lookup (compiler_env, fname,
-                         &back, &over);
+  decl = pkl_env_lookup (compiler_env, PKL_ENV_NS_MAIN,
+                         fname, &back, &over);
 
   if (decl == NULL)
     {
diff --git a/src/pkl-anal.c b/src/pkl-anal.c
index 989851b..c781b85 100644
--- a/src/pkl-anal.c
+++ b/src/pkl-anal.c
@@ -414,6 +414,29 @@ PKL_PHASE_BEGIN_HANDLER (pkl_anal1_ps_op_sl)
 }
 PKL_PHASE_END_HANDLER
 
+/* The initializing expressions in unit declarations should be integer
+   nodes.  Note this handler runs after the unit is
+   constant-folded.  */
+
+PKL_PHASE_BEGIN_HANDLER (pkl_anal1_ps_decl)
+{
+  pkl_ast_node decl = PKL_PASS_NODE;
+
+  if (PKL_AST_DECL_KIND (decl) == PKL_AST_DECL_KIND_UNIT)
+    {
+      pkl_ast_node initial = PKL_AST_DECL_INITIAL (decl);
+
+      if (PKL_AST_CODE (initial) != PKL_AST_INTEGER)
+        {
+          PKL_ERROR (PKL_AST_LOC (initial),
+                     "expected constant integral value for unit");
+          PKL_ANAL_PAYLOAD->errors++;
+          PKL_PASS_ERROR;
+        }
+    }
+}
+PKL_PHASE_END_HANDLER
+
 struct pkl_phase pkl_phase_anal1 =
   {
    PKL_PHASE_PR_HANDLER (PKL_AST_PROGRAM, pkl_anal_pr_program),
@@ -424,6 +447,7 @@ struct pkl_phase pkl_phase_anal1 =
    PKL_PHASE_PS_HANDLER (PKL_AST_FUNC, pkl_anal1_ps_func),
    PKL_PHASE_PS_HANDLER (PKL_AST_RETURN_STMT, pkl_anal1_ps_return_stmt),
    PKL_PHASE_PS_HANDLER (PKL_AST_OFFSET, pkl_anal1_ps_offset),
+   PKL_PHASE_PS_HANDLER (PKL_AST_DECL, pkl_anal1_ps_decl),
    PKL_PHASE_PR_HANDLER (PKL_AST_TYPE, pkl_anal_pr_type),
    PKL_PHASE_PS_TYPE_HANDLER (PKL_TYPE_STRUCT, pkl_anal1_ps_type_struct),
    PKL_PHASE_PS_TYPE_HANDLER (PKL_TYPE_FUNCTION, pkl_anal1_ps_type_function),
diff --git a/src/pkl-asm.c b/src/pkl-asm.c
index 6eed504..7a03c14 100644
--- a/src/pkl-asm.c
+++ b/src/pkl-asm.c
@@ -1864,8 +1864,8 @@ pkl_asm_call (pkl_asm pasm, const char *funcname)
   int back, over;
   pkl_ast_node tmp;
 
-  tmp = pkl_env_lookup (compiler_env, funcname,
-                        &back, &over);
+  tmp = pkl_env_lookup (compiler_env, PKL_ENV_NS_MAIN,
+                        funcname, &back, &over);
   assert (tmp != NULL);
 
   pkl_asm_insn (pasm, PKL_INSN_PUSHVAR, back, over);
diff --git a/src/pkl-ast.c b/src/pkl-ast.c
index bfbcba1..e6f5164 100644
--- a/src/pkl-ast.c
+++ b/src/pkl-ast.c
@@ -1324,49 +1324,6 @@ pkl_ast_make_offset (pkl_ast ast,
   return offset;
 }
 
-/* Get an identifier with the name of a predefined offset unit (like
-   b, B, Kb, etc) and return an integral expression evaluating to its
-   number of bits.  If the identifier doesn't identify a predefined
-   offset unit, return NULL.  */
-
-pkl_ast_node
-pkl_ast_id_to_offset_unit (pkl_ast ast, pkl_ast_node id)
-{
-  pkl_ast_node unit, unit_type;
-  size_t factor = 0;
-  const char *id_pointer = PKL_AST_IDENTIFIER_POINTER (id);
-
-  /* XXX: replace this with a pkl-units.def file.  */
-  if (STREQ (id_pointer, "b"))
-    factor = PKL_AST_OFFSET_UNIT_BITS;
-  else if (STREQ (id_pointer, "N"))
-    factor = PKL_AST_OFFSET_UNIT_NIBBLES;
-  else if (STREQ (id_pointer, "B"))
-    factor = PKL_AST_OFFSET_UNIT_BYTES;
-  else if (STREQ (id_pointer, "Kb"))
-    factor = PKL_AST_OFFSET_UNIT_KILOBITS;
-  else if (STREQ (id_pointer, "KB"))
-    factor =  PKL_AST_OFFSET_UNIT_KILOBYTES;
-  else if (STREQ (id_pointer, "Mb"))
-    factor = PKL_AST_OFFSET_UNIT_MEGABITS;
-  else if (STREQ (id_pointer, "MB"))
-    factor = PKL_AST_OFFSET_UNIT_MEGABYTES;
-  else if (STREQ (id_pointer, "Gb"))
-    factor = PKL_AST_OFFSET_UNIT_GIGABITS;
-  else
-    /* Invalid offset unit.  */
-    return NULL;
-
-  unit_type = pkl_ast_make_integral_type (ast, 64, 0);
-  PKL_AST_LOC (unit_type) = PKL_AST_LOC (id);
-
-  unit = pkl_ast_make_integer (ast, factor);
-  PKL_AST_LOC (unit) = PKL_AST_LOC (id);
-  PKL_AST_TYPE (unit) = ASTREF (unit_type);
-
-  return unit;
-}
-
 /* Build and return an AST node for a cast.  */
 
 pkl_ast_node
diff --git a/src/pkl-ast.h b/src/pkl-ast.h
index c70e920..7ee65ed 100644
--- a/src/pkl-ast.h
+++ b/src/pkl-ast.h
@@ -936,8 +936,8 @@ pkl_ast_node pkl_struct_type_traverse (pkl_ast_node type, 
const char *path);
    function, type, variable....
 
    KIND allows to quickly identify the nature of the entity being
-   declared: PKL_AST_DECL_KIND_VAR, PKL_AST_DECL_KIND_TYPE or
-   PKL_AST_DECL_KIND_FUNC.
+   declared: PKL_AST_DECL_KIND_VAR, PKL_AST_DECL_KIND_TYPE,
+   PKL_AST_DECL_KIND_FUNC or PKL_AST_DECL_KIND_UNIT.
 
    NAME is PKL_AST_IDENTIFIER node containing the name in the
    association.
@@ -947,6 +947,7 @@ pkl_ast_node pkl_struct_type_traverse (pkl_ast_node type, 
const char *path);
    - An expression node for a variable.
    - A PKL_AST_TYPE for a type.
    - A PKL_AST_FUNC for a function.
+   - A constant expression node for an unit.
 
    ORDER is the order of the declaration in its containing
    compile-time environment.  It is filled up when the declaration is
@@ -967,6 +968,7 @@ pkl_ast_node pkl_struct_type_traverse (pkl_ast_node type, 
const char *path);
 #define PKL_AST_DECL_KIND_VAR 1
 #define PKL_AST_DECL_KIND_TYPE 2
 #define PKL_AST_DECL_KIND_FUNC 3
+#define PKL_AST_DECL_KIND_UNIT 4
 
 struct pkl_ast_decl
 {
@@ -1012,9 +1014,6 @@ pkl_ast_node pkl_ast_make_offset (pkl_ast ast,
                                   pkl_ast_node magnitude,
                                   pkl_ast_node unit);
 
-pkl_ast_node pkl_ast_id_to_offset_unit (pkl_ast ast,
-                                        pkl_ast_node id);
-
 /* PKL_AST_CAST nodes represent casts at the language level.
 
    TYPE is the target type in the case.
diff --git a/src/pkl-env.c b/src/pkl-env.c
index ecde48d..6d6d108 100644
--- a/src/pkl-env.c
+++ b/src/pkl-env.c
@@ -27,9 +27,15 @@
 #define STREQ(a, b) (strcmp (a, b) == 0)
 
 /* The declarations are organized in a hash table, chained in their
-   buckes through CHAIN2.  Note that in Pkl an unique namespace is
-   shared by types, variables and functions, so only one table is
-   required.
+   buckes through CHAIN2.
+
+   There are two namespaces in Poke:
+
+   - A main namespace, shared by types, variables and functions.
+     HASH_TABLE is used to store declarations for these entities.
+
+   - A separated namespace for offset units.  UNITS_HASH_TABLE is used
+     to store declarations for these.
 
    UP is a link to the immediately enclosing frame.  This is NULL for
    the top-level frame.  */
@@ -40,9 +46,11 @@ typedef pkl_ast_node pkl_hash[HASH_TABLE_SIZE];
 struct pkl_env
 {
   pkl_hash hash_table;
+  pkl_hash units_hash_table;
 
   int num_types;
   int num_vars;
+  int num_units;
 
   struct pkl_env *up;
 };
@@ -95,6 +103,7 @@ get_registered (pkl_hash hash_table, const char *name)
   for (t = hash_table[hash]; t != NULL; t = PKL_AST_CHAIN2 (t))
     {
       pkl_ast_node t_name = PKL_AST_DECL_NAME (t);
+
       if (STREQ (PKL_AST_IDENTIFIER_POINTER (t_name),
                  name))
         return t;
@@ -122,6 +131,26 @@ register_decl (pkl_hash hash_table,
   return 1;
 }
 
+static pkl_hash *
+get_ns_table (pkl_env env, int namespace)
+{
+  pkl_hash *table = NULL;
+
+  switch (namespace)
+    {
+    case PKL_ENV_NS_MAIN:
+      table = &env->hash_table;
+      break;
+    case PKL_ENV_NS_UNITS:
+      table = &env->units_hash_table;
+      break;
+    default:
+      assert (0);
+    }
+
+  return table;
+}
+
 /* The following functions are documented in pkl-env.h.  */
 
 pkl_env
@@ -137,6 +166,7 @@ pkl_env_free (pkl_env env)
     {
       pkl_env_free (env->up);
       free_hash_table (env->hash_table);
+      free_hash_table (env->units_hash_table);
       free (env);
     }
 }
@@ -165,10 +195,13 @@ pkl_env_pop_frame (pkl_env env)
 
 int
 pkl_env_register (pkl_env env,
+                  int namespace,
                   const char *name,
                   pkl_ast_node decl)
 {
-  if (register_decl (env->hash_table, name, decl))
+  pkl_hash *table = get_ns_table (env, namespace);
+  
+  if (register_decl (*table, name, decl))
     {
       switch (PKL_AST_DECL_KIND (decl))
         {
@@ -179,6 +212,9 @@ pkl_env_register (pkl_env env,
         case PKL_AST_DECL_KIND_FUNC:
           PKL_AST_DECL_ORDER (decl) = env->num_vars++;
           break;
+        case PKL_AST_DECL_KIND_UNIT:
+          PKL_AST_DECL_ORDER (decl) = env->num_units++;
+          break;
         default:
           assert (0);
         }
@@ -189,14 +225,15 @@ pkl_env_register (pkl_env env,
 }
 
 static pkl_ast_node
-pkl_env_lookup_1 (pkl_env env, const char *name,
+pkl_env_lookup_1 (pkl_env env, int namespace, const char *name,
                   int *back, int *over, int num_frame)
 {
   if (env == NULL)
     return NULL;
   else
     {
-      pkl_ast_node decl = get_registered (env->hash_table, name);
+      pkl_hash *table = get_ns_table (env, namespace);
+      pkl_ast_node decl = get_registered (*table, name);
 
       if (decl)
         {
@@ -208,15 +245,15 @@ pkl_env_lookup_1 (pkl_env env, const char *name,
         }
     }
 
-  return pkl_env_lookup_1 (env->up, name, back, over,
+  return pkl_env_lookup_1 (env->up, namespace, name, back, over,
                            num_frame + 1);
 }
 
 pkl_ast_node
-pkl_env_lookup (pkl_env env, const char *name,
+pkl_env_lookup (pkl_env env, int namespace, const char *name,
                 int *back, int *over)
 {
-  return pkl_env_lookup_1 (env, name, back, over, 0);
+  return pkl_env_lookup_1 (env, namespace, name, back, over, 0);
 }
 
 int
@@ -285,18 +322,30 @@ pkl_env_dup_toplevel (pkl_env env)
   assert (pkl_env_toplevel_p (env));
 
   new = pkl_env_new ();
+
   for (i = 0; i < HASH_TABLE_SIZE; ++i)
     {
       pkl_ast_node t;
-
       pkl_ast_node decl = env->hash_table[i];
+
       for (t = decl; t; t = PKL_AST_CHAIN2 (t))
         t = ASTREF (t);
       new->hash_table[i] = decl;
     }
 
+  for (i = 0; i < HASH_TABLE_SIZE; ++i)
+    {
+      pkl_ast_node t;
+      pkl_ast_node decl = env->units_hash_table[i];
+
+      for (t = decl; t; t = PKL_AST_CHAIN2 (t))
+        t = ASTREF (t);
+      new->units_hash_table[i] = decl;
+    }
+
   new->num_types = env->num_types;
   new->num_vars = env->num_vars;
+  new->num_units = env->num_units;
 
   return new;
 }
@@ -324,7 +373,7 @@ pkl_env_get_next_matching_decl (pkl_env env, struct 
pkl_ast_node_iter *iter,
          pkl_env_iter_next (env, iter);
           continue;
        }
-      return  strdup (cmdname);
+      return strdup (cmdname);
     }
   return NULL;
 }
diff --git a/src/pkl-env.h b/src/pkl-env.h
index 4799c0c..c3ff0f4 100644
--- a/src/pkl-env.h
+++ b/src/pkl-env.h
@@ -58,6 +58,14 @@
 
 typedef struct pkl_env *pkl_env;  /* Struct defined in pkl-env.c */
 
+/* Declarations in Poke live in two different, separated name spaces:
+
+   The `main' namespace, shared by types, variables and functions.
+   The `units' namespace, for offset units.  */
+
+#define PKL_ENV_NS_MAIN 0
+#define PKL_ENV_NS_UNITS 1
+
 /* Get an empty environment.  */
 
 pkl_env pkl_env_new (void);
@@ -77,18 +85,19 @@ pkl_env pkl_env_push_frame (pkl_env env);
 
 pkl_env pkl_env_pop_frame (pkl_env env);
 
-/* Register the declaration DECL in the current frame under NAME.
-   Return 1 if the declaration was properly registered.  Return 0 if
-   there is already a declaration with the given name in the current
-   frame.  */
+/* Register the declaration DECL in the current frame under NAME in
+   the given NAMESPACE.  Return 1 if the declaration was properly
+   registered.  Return 0 if there is already a declaration with the
+   given name in the current frame and namespace.  */
 
 int pkl_env_register (pkl_env env,
+                      int namespace,
                       const char *name,
                       pkl_ast_node decl);
 
-/* Search in the environment ENV for a declaration with name NAME, put
-   the lexical address of the first match in BACK and OVER if these
-   are not NULL.  Return the declaration node.
+/* Search in the environment ENV for a declaration with name NAME in
+   the given NAMESPACE, put the lexical address of the first match in
+   BACK and OVER if these are not NULL.  Return the declaration node.
 
    BACK is the number of frames back the declaration is located.  It
    is 0-based.
@@ -96,7 +105,8 @@ int pkl_env_register (pkl_env env,
    OVER indicates its position in the list of declarations in the
    resulting frame.  It is 0-based.  */
 
-pkl_ast_node pkl_env_lookup (pkl_env env, const char *name,
+pkl_ast_node pkl_env_lookup (pkl_env env, int namespace,
+                             const char *name,
                              int *back, int *over);
 
 /* Return 1 if the given ENV contains only one frame.  Return 0
@@ -123,6 +133,8 @@ void pkl_env_map_decls (pkl_env env,
 pkl_env pkl_env_dup_toplevel (pkl_env env);
 
 
+/* The following iterators work on the main namespace.  */
+
 struct pkl_ast_node_iter
 {
   int bucket;        /* The bucket in which this node resides.  */
diff --git a/src/pkl-fold.c b/src/pkl-fold.c
index 4890d78..4b8271d 100644
--- a/src/pkl-fold.c
+++ b/src/pkl-fold.c
@@ -809,16 +809,26 @@ PKL_PHASE_BEGIN_HANDLER (pkl_fold_ps_cast)
         = (PKL_AST_INTEGER_VALUE (magnitude) *
            PKL_AST_INTEGER_VALUE (unit));
 
-      /* Calculate the new unit.  */
-      PKL_AST_INTEGER_VALUE (unit)
-        = PKL_AST_INTEGER_VALUE (to_unit);
+      /* Calculate the new unit.  It should always be a new node,
+         since otherwise we may be chaning an integer node that is
+         also part of an unit declaration, or who knows what.  */
+      {
+        pkl_ast_node unit_type = PKL_AST_TYPE (unit);
+        pkl_ast_node new_unit
+          =  pkl_ast_make_integer (PKL_PASS_AST,
+                                   PKL_AST_INTEGER_VALUE (to_unit));
+
+        PKL_AST_TYPE (new_unit) = ASTREF (unit_type);
+        PKL_AST_LOC (new_unit) = PKL_AST_LOC (unit);
+        unit = new_unit;
+      }
 
       /* We may need to create a new magnitude node, if the base type
          is different.  */
       if (!pkl_ast_type_equal (from_base_type, to_base_type))
         {
-          magnitude = pkl_ast_make_integer  (PKL_PASS_AST,
-                                             PKL_AST_INTEGER_VALUE 
(magnitude));
+          magnitude = pkl_ast_make_integer (PKL_PASS_AST,
+                                            PKL_AST_INTEGER_VALUE (magnitude));
           PKL_AST_TYPE (magnitude) = ASTREF (to_base_type);
           PKL_AST_LOC (magnitude) = PKL_AST_LOC (cast);
         }
@@ -828,7 +838,6 @@ PKL_PHASE_BEGIN_HANDLER (pkl_fold_ps_cast)
         = (PKL_AST_INTEGER_VALUE (magnitude)
            /  PKL_AST_INTEGER_VALUE (unit));
 
-
       new = pkl_ast_make_offset (PKL_PASS_AST,
                                  magnitude, unit);
     }
diff --git a/src/pkl-gen.c b/src/pkl-gen.c
index 2693b7a..08d5cc5 100644
--- a/src/pkl-gen.c
+++ b/src/pkl-gen.c
@@ -119,6 +119,10 @@ PKL_PHASE_BEGIN_HANDLER (pkl_gen_pr_decl)
 
   switch (PKL_AST_DECL_KIND (decl))
     {
+    case PKL_AST_DECL_KIND_UNIT:
+      /* Nothing to do with units at run-time, for now.  */
+      PKL_PASS_BREAK;
+      break;
     case PKL_AST_DECL_KIND_TYPE:
       switch (PKL_AST_TYPE_CODE (initial))
         {
diff --git a/src/pkl-lex.l b/src/pkl-lex.l
index 7beca05..6451630 100644
--- a/src/pkl-lex.l
+++ b/src/pkl-lex.l
@@ -203,6 +203,7 @@ D [0-9]
 "defun"                { return DEFUN; }
 "deftype"      { return DEFTYPE; }
 "defvar"       { return DEFVAR; }
+"defunit"      { return DEFUNIT; }
 "break"                { return BREAK; }
 "return"        { return RETURN; }
 "string"       { return STRING; }
@@ -306,19 +307,29 @@ D [0-9]
 
 #{L}({L}|{D})* {
    pkl_ast_node decl
-       = pkl_env_lookup (yyextra->env, yytext + 1, NULL, NULL);
+      = pkl_env_lookup (yyextra->env, PKL_ENV_NS_UNITS,
+                        yytext + 1, NULL, NULL);
 
-   if (decl && PKL_AST_DECL_KIND (decl) == PKL_AST_DECL_KIND_TYPE)
+   if (decl)
      yylval->ast = PKL_AST_DECL_INITIAL (decl);
    else
-     yylval->ast = pkl_ast_make_identifier (yyextra->ast, yytext + 1);
+     {
+       decl = pkl_env_lookup (yyextra->env, PKL_ENV_NS_MAIN,
+                              yytext + 1, NULL, NULL);
+
+       if (decl && PKL_AST_DECL_KIND (decl) == PKL_AST_DECL_KIND_TYPE)
+         yylval->ast = PKL_AST_DECL_INITIAL (decl);
+       else
+         yylval->ast = NULL;
+     }
 
    return UNIT;
 }
 
 {L}({L}|{D})* {
    pkl_ast_node decl
-       = pkl_env_lookup (yyextra->env, yytext, NULL, NULL);
+     = pkl_env_lookup (yyextra->env, PKL_ENV_NS_MAIN,
+                       yytext, NULL, NULL);
 
    yylval->ast = pkl_ast_make_identifier (yyextra->ast, yytext);
 
diff --git a/src/pkl-tab.y b/src/pkl-tab.y
index 87e970a..ac969ed 100644
--- a/src/pkl-tab.y
+++ b/src/pkl-tab.y
@@ -93,6 +93,7 @@ pkl_register_arg (struct pkl_parser *parser, pkl_ast_node arg)
   PKL_AST_LOC (arg_decl) = PKL_AST_LOC (arg);
 
   if (!pkl_env_register (parser->env,
+                         PKL_ENV_NS_MAIN,
                          PKL_AST_IDENTIFIER_POINTER (arg_identifier),
                          arg_decl))
     {
@@ -134,6 +135,7 @@ pkl_register_args (struct pkl_parser *parser, pkl_ast_node 
arg_list)
       PKL_AST_LOC (arg_decl) = PKL_AST_LOC (arg);
 
       if (!pkl_env_register (parser->env,
+                             PKL_ENV_NS_MAIN,
                              PKL_AST_IDENTIFIER_POINTER (arg_identifier),
                              arg_decl))
         {
@@ -169,7 +171,7 @@ pkl_register_dummies (struct pkl_parser *parser, int n)
                                 id, NULL /* initial */,
                                 NULL /* source */);
 
-      r = pkl_env_register (parser->env, name, decl);
+      r = pkl_env_register (parser->env, PKL_ENV_NS_MAIN, name, decl);
       assert (r);
     }
 }
@@ -318,7 +320,7 @@ load_module (struct pkl_parser *parser,
 %token ASSERT
 %token ERR
 %token INTCONSTR UINTCONSTR OFFSETCONSTR
-%token DEFUN DEFSET DEFTYPE DEFVAR
+%token DEFUN DEFSET DEFTYPE DEFVAR DEFUNIT
 %token RETURN BREAK
 %token STRING
 %token TRY CATCH RAISE
@@ -733,6 +735,7 @@ expression:
                   pkl_ast_node astruct;
 
                   pkl_ast_node decl = pkl_env_lookup (pkl_parser->env,
+                                                      PKL_ENV_NS_MAIN,
                                                       
PKL_AST_IDENTIFIER_POINTER ($1),
                                                       NULL, NULL);
                   assert (decl != NULL
@@ -765,6 +768,13 @@ expression:
                }
         | UNIT
                {
+                  if ($1 == NULL)
+                    {
+                      pkl_error (pkl_parser->compiler, pkl_parser->ast, @1,
+                                 "invalid unit in offset");
+                      YYERROR;
+                    }
+                  
                     $$ = pkl_ast_make_offset (pkl_parser->ast, NULL, $1);
                     PKL_AST_LOC ($1) = @1;
                     if (PKL_AST_TYPE ($1))
@@ -773,6 +783,13 @@ expression:
                 }
         | expression UNIT
                {
+                  if ($2 == NULL)
+                    {
+                      pkl_error (pkl_parser->compiler, pkl_parser->ast, @2,
+                                 "invalid unit in offset");
+                      YYERROR;
+                    }
+
                     $$ = pkl_ast_make_offset (pkl_parser->ast, $1, $2);
                     PKL_AST_LOC ($2) = @2;
                     if (PKL_AST_TYPE ($2))
@@ -827,6 +844,7 @@ primary:
 
                   pkl_ast_node decl
                     = pkl_env_lookup (pkl_parser->env,
+                                      PKL_ENV_NS_MAIN,
                                       name, &back, &over);
                   if (!decl
                       || (PKL_AST_DECL_KIND (decl) != PKL_AST_DECL_KIND_VAR
@@ -1101,6 +1119,7 @@ simple_type_specifier:
          TYPENAME
                {
                   pkl_ast_node decl = pkl_env_lookup (pkl_parser->env,
+                                                      PKL_ENV_NS_MAIN,
                                                       
PKL_AST_IDENTIFIER_POINTER ($1),
                                                       NULL, NULL);
                   assert (decl != NULL
@@ -1147,18 +1166,36 @@ integral_type_sign:
        ;
 
 offset_type_specifier:
-          OFFSETCONSTR simple_type_specifier ',' IDENTIFIER '>'
+          OFFSETCONSTR simple_type_specifier ',' identifier '>'
                 {
-                    $$ = pkl_ast_make_offset_type (pkl_parser->ast,
-                                                   $2, $4);
-                    PKL_AST_LOC ($4) = @4;
-                    PKL_AST_LOC ($$) = @$;
-                }
-        | OFFSETCONSTR simple_type_specifier ',' simple_type_specifier '>'
-                {
-                    $$ = pkl_ast_make_offset_type (pkl_parser->ast,
-                                                   $2, $4);
-                    PKL_AST_LOC ($$) = @$;
+                  pkl_ast_node decl
+                    = pkl_env_lookup (pkl_parser->env,
+                                      PKL_ENV_NS_UNITS,
+                                      PKL_AST_IDENTIFIER_POINTER ($4),
+                                      NULL, NULL);
+
+                  if (!decl)
+                    {
+                      /* This could be the name of a type.  Try it out.  */
+                      decl = pkl_env_lookup (pkl_parser->env,
+                                             PKL_ENV_NS_MAIN,
+                                             PKL_AST_IDENTIFIER_POINTER ($4),
+                                             NULL, NULL);
+                      
+                      if (!decl)
+                        {
+                          pkl_error (pkl_parser->compiler, pkl_parser->ast, @4,
+                                     "invalid unit in offset type");
+                          YYERROR;
+                        }
+                    }
+
+                  $$ = pkl_ast_make_offset_type (pkl_parser->ast,
+                                                 $2,
+                                                 PKL_AST_DECL_INITIAL (decl));
+
+                  ASTREF ($4); pkl_ast_node_free ($4);
+                  PKL_AST_LOC ($$) = @$;
                 }
         | OFFSETCONSTR simple_type_specifier ',' INTEGER '>'
                {
@@ -1325,6 +1362,7 @@ struct_type_field:
                       PKL_AST_LOC (decl) = @$;
 
                       if (!pkl_env_register (pkl_parser->env,
+                                             PKL_ENV_NS_MAIN,
                                              PKL_AST_IDENTIFIER_POINTER ($3),
                                              decl))
                         {
@@ -1411,6 +1449,7 @@ declaration:
                   PKL_AST_LOC ($<ast>$) = @$;
 
                   if (!pkl_env_register (pkl_parser->env,
+                                         PKL_ENV_NS_MAIN,
                                          PKL_AST_IDENTIFIER_POINTER ($2),
                                          $<ast>$))
                     {
@@ -1460,6 +1499,7 @@ declaration:
                   PKL_AST_LOC ($$) = @$;
 
                   if (!pkl_env_register (pkl_parser->env,
+                                         PKL_ENV_NS_MAIN,
                                          PKL_AST_IDENTIFIER_POINTER ($2),
                                          $$))
                     {
@@ -1482,6 +1522,7 @@ declaration:
                   PKL_AST_TYPE_NAME ($4) = ASTREF ($2);
 
                   if (!pkl_env_register (pkl_parser->env,
+                                         PKL_ENV_NS_MAIN,
                                          PKL_AST_IDENTIFIER_POINTER ($2),
                                          $$))
                     {
@@ -1493,6 +1534,39 @@ declaration:
                       YYERROR;
                     }
                 }
+       | DEFUNIT identifier '=' expression ';'
+               {
+                  /* We need to cast the expression to uint<64> here,
+                     instead of pkl-promo, because the installed
+                     initializer is used as earlier as in the
+                     lexer.  Not pretty.  */
+                  pkl_ast_node type
+                    = pkl_ast_make_integral_type (pkl_parser->ast,
+                                                  64, 0);
+                  pkl_ast_node cast
+                    = pkl_ast_make_cast (pkl_parser->ast,
+                                         type, $4);
+                  
+                  $$ = pkl_ast_make_decl (pkl_parser->ast,
+                                          PKL_AST_DECL_KIND_UNIT, $2, cast,
+                                          pkl_parser->filename);
+
+                  PKL_AST_LOC (type) = @4;
+                  PKL_AST_LOC (cast) = @4;
+                  PKL_AST_LOC ($2) = @2;
+                  PKL_AST_LOC ($$) = @$;
+
+                  if (!pkl_env_register (pkl_parser->env,
+                                         PKL_ENV_NS_UNITS,
+                                         PKL_AST_IDENTIFIER_POINTER ($2),
+                                         $$))
+                    {
+                      pkl_error (pkl_parser->compiler, pkl_parser->ast, @2,
+                                 "the unit `%s' is already defined",
+                                 PKL_AST_IDENTIFIER_POINTER ($2));
+                      YYERROR;
+                    }
+                }
         ;
 
 /*
@@ -1614,6 +1688,7 @@ stmt:
                   PKL_AST_LOC ($<ast>$) = @3;
 
                   if (!pkl_env_register (pkl_parser->env,
+                                         PKL_ENV_NS_MAIN,
                                          PKL_AST_IDENTIFIER_POINTER ($3),
                                          $<ast>$))
                     /* This should never happen.  */
@@ -1659,6 +1734,7 @@ stmt:
                   PKL_AST_LOC ($<ast>$) = @3;
 
                   if (!pkl_env_register (pkl_parser->env,
+                                         PKL_ENV_NS_MAIN,
                                          PKL_AST_IDENTIFIER_POINTER ($3),
                                          $<ast>$))
                     /* This should never happen.  */
diff --git a/src/pkl-trans.c b/src/pkl-trans.c
index 4d675cb..e637db6 100644
--- a/src/pkl-trans.c
+++ b/src/pkl-trans.c
@@ -234,18 +234,12 @@ PKL_PHASE_BEGIN_HANDLER (pkl_trans1_ps_type_struct)
 }
 PKL_PHASE_END_HANDLER
 
-/* At this point offsets can have either an identifier, an integer or
-   a type expressing its unit.  This handler takes care of the first
-   case, replacing the identifier with a suitable unit factor.  If the
-   identifier is invalid, then an error is raised.
-
-   Also, if the magnitude of the offset wasn't specified then it
-   defaults to 1. */
+/* If the magnitude of an offset is not specified then it defaults to
+   1. */
 
 PKL_PHASE_BEGIN_HANDLER (pkl_trans1_ps_offset)
 {
   pkl_ast_node offset = PKL_PASS_NODE;
-  pkl_ast_node unit = PKL_AST_OFFSET_UNIT (offset);
 
   if (PKL_AST_OFFSET_MAGNITUDE (offset) == NULL)
     {
@@ -261,54 +255,6 @@ PKL_PHASE_BEGIN_HANDLER (pkl_trans1_ps_offset)
       PKL_AST_OFFSET_MAGNITUDE (offset) = ASTREF (magnitude);
       PKL_PASS_RESTART = 1;
     }
-
-  if (PKL_AST_CODE (unit) == PKL_AST_IDENTIFIER)
-    {
-      pkl_ast_node new_unit
-        = pkl_ast_id_to_offset_unit (PKL_PASS_AST, unit);
-
-      if (!new_unit)
-        {
-          PKL_ERROR (PKL_AST_LOC (unit),
-                     "expected `b', `N', `B', `Kb', `KB', `Mb', 'MB' or `Gb'");
-          PKL_TRANS_PAYLOAD->errors++;
-          PKL_PASS_ERROR;
-        }
-
-      PKL_AST_OFFSET_UNIT (offset) = ASTREF (new_unit);
-      pkl_ast_node_free (unit);
-      PKL_PASS_RESTART = 1;
-    }
-}
-PKL_PHASE_END_HANDLER
-
-/* At this point offset types can have an identifier expressing its
-   units.  This handler replaces the identifier with a suitable unit
-   factor.  If the identifier is invalid, then an error is raised.
-   XXX: to remove.  */
-
-PKL_PHASE_BEGIN_HANDLER (pkl_trans1_ps_type_offset)
-{
-  pkl_ast_node offset_type = PKL_PASS_NODE;
-  pkl_ast_node unit = PKL_AST_TYPE_O_UNIT (offset_type);
-
-  if (PKL_AST_CODE (unit) == PKL_AST_IDENTIFIER)
-    {
-      pkl_ast_node new_unit
-        = pkl_ast_id_to_offset_unit (PKL_PASS_AST, unit);
-
-      if (!new_unit)
-        {
-          PKL_ERROR (PKL_AST_LOC (unit),
-                     "expected `b', `B', `Kb', `KB', `Mb', 'MB' or `Gb'");
-          PKL_TRANS_PAYLOAD->errors++;
-          PKL_PASS_ERROR;
-        }
-
-      PKL_AST_TYPE_O_UNIT (offset_type) = ASTREF (new_unit);
-      pkl_ast_node_free (unit);
-      PKL_PASS_RESTART = 1;
-    }
 }
 PKL_PHASE_END_HANDLER
 
@@ -1063,7 +1009,6 @@ struct pkl_phase pkl_phase_trans1 =
    PKL_PHASE_PR_HANDLER (PKL_AST_TYPE, pkl_trans_pr_type),
    PKL_PHASE_PS_OP_HANDLER (PKL_AST_OP_ATTR, pkl_trans1_ps_op_attr),
    PKL_PHASE_PS_TYPE_HANDLER (PKL_TYPE_STRUCT, pkl_trans1_ps_type_struct),
-   PKL_PHASE_PS_TYPE_HANDLER (PKL_TYPE_OFFSET, pkl_trans1_ps_type_offset),
    PKL_PHASE_PS_TYPE_HANDLER (PKL_TYPE_FUNCTION, pkl_trans1_ps_type_function),
   };
 
@@ -1229,7 +1174,7 @@ PKL_PHASE_BEGIN_HANDLER (pkl_trans2_ps_offset_type)
 
   if (PKL_AST_TYPE_COMPLETE (unit_type) != PKL_AST_TYPE_COMPLETE_YES)
     {
-      PKL_ERROR (PKL_AST_LOC (unit_type),
+      PKL_ERROR (PKL_AST_LOC (type),
                  "offset types only work on complete types");
       PKL_TRANS_PAYLOAD->errors++;
       PKL_PASS_ERROR;
diff --git a/src/std.pk b/src/std.pk
index 39e2ca9..2426730 100644
--- a/src/std.pk
+++ b/src/std.pk
@@ -16,6 +16,18 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+/*** Standard units.  */
+
+defunit b = 1;
+defunit N = 4;
+defunit B = 8;
+defunit Kb = 1024;
+defunit KB = 1024 * 8;
+defunit Mb = 1024UL * 1024;
+defunit MB = 1024UL * 1024 * 8;
+defunit Gb = 1024UL * 1024 * 1024;
+defunit GB = 1024UL * 1024 * 1024 * 8;
+
 /*** Standard Integral Types.  */
 
 deftype bit = uint<1>;
diff --git a/testsuite/poke.pkl/units-1.pk b/testsuite/poke.pkl/units-1.pk
new file mode 100644
index 0000000..bf2e4a8
--- /dev/null
+++ b/testsuite/poke.pkl/units-1.pk
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+
+defunit x = 3UL;
+
+/* { dg-command { 2#x } } */
+/* { dg-output "2#3" } */
diff --git a/testsuite/poke.pkl/units-2.pk b/testsuite/poke.pkl/units-2.pk
new file mode 100644
index 0000000..d169d66
--- /dev/null
+++ b/testsuite/poke.pkl/units-2.pk
@@ -0,0 +1,8 @@
+/* { dg-do run } */
+
+/* This tests that expressions in defunit are properly promoted.  */
+
+defunit x = 3;
+
+/* { dg-command { 2#x } } */
+/* { dg-output "2#3" } */
diff --git a/testsuite/poke.pkl/units-3.pk b/testsuite/poke.pkl/units-3.pk
new file mode 100644
index 0000000..a82ff8c
--- /dev/null
+++ b/testsuite/poke.pkl/units-3.pk
@@ -0,0 +1,8 @@
+/* { dg-do run } */
+
+/* This tests that expressions in defunit are properly promoted.  */
+
+defunit x = 3 as int<3>;
+
+/* { dg-command { 2#x } } */
+/* { dg-output "2#3" } */
diff --git a/testsuite/poke.pkl/units-4.pk b/testsuite/poke.pkl/units-4.pk
new file mode 100644
index 0000000..960d058
--- /dev/null
+++ b/testsuite/poke.pkl/units-4.pk
@@ -0,0 +1,10 @@
+/* { dg-do run } */
+
+/* This tests that expressions in defunit are properly promoted.  */
+
+defunit x = 3;
+
+defun foo = uint<64>: { defunit x = 4; return 1#x'unit; }
+
+/* { dg-command { foo } } */
+/* { dg-output "4UL" } */
diff --git a/testsuite/poke.pkl/units-5.pk b/testsuite/poke.pkl/units-5.pk
new file mode 100644
index 0000000..4432db4
--- /dev/null
+++ b/testsuite/poke.pkl/units-5.pk
@@ -0,0 +1,10 @@
+/* { dg-do run } */
+
+/* This tests that expressions in defunit are properly promoted.  */
+
+defunit x = 3;
+
+defun foo = uint<64>: { return 1#x'unit; }
+
+/* { dg-command { foo } } */
+/* { dg-output "3UL" } */
diff --git a/testsuite/poke.pkl/units-6.pk b/testsuite/poke.pkl/units-6.pk
new file mode 100644
index 0000000..792fc17
--- /dev/null
+++ b/testsuite/poke.pkl/units-6.pk
@@ -0,0 +1,10 @@
+/* { dg-do run } */
+
+/* Make sure that units take prececence to type names in offset
+   literals.  */
+
+deftype y = int;
+defunit y = 3;
+
+/* { dg-command { 2#y } } */
+/* { dg-output "2#3" } */
diff --git a/testsuite/poke.pkl/units-7.pk b/testsuite/poke.pkl/units-7.pk
new file mode 100644
index 0000000..6aa0546
--- /dev/null
+++ b/testsuite/poke.pkl/units-7.pk
@@ -0,0 +1,11 @@
+/* { dg-do run } */
+
+/* Make sure that units take prececence to type names in offset
+   types.  */
+
+deftype y = int;
+defunit y = 3;
+deftype myoff = offset<int,y>;
+
+/* { dg-command { 6#b as myoff } } */
+/* { dg-output "2#3" } */
diff --git a/testsuite/poke.pkl/units-diag-1.pk 
b/testsuite/poke.pkl/units-diag-1.pk
new file mode 100644
index 0000000..9eb7720
--- /dev/null
+++ b/testsuite/poke.pkl/units-diag-1.pk
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+
+defunit x = [1,2,3]; /* { dg-error "" } */
diff --git a/testsuite/poke.pkl/units-diag-2.pk 
b/testsuite/poke.pkl/units-diag-2.pk
new file mode 100644
index 0000000..c6d6c1c
--- /dev/null
+++ b/testsuite/poke.pkl/units-diag-2.pk
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+
+defun foo = string: { return "foo"; }
+
+defunit x = foo; /* { dg-error "" } */
diff --git a/testsuite/poke.pkl/units-diag-3.pk 
b/testsuite/poke.pkl/units-diag-3.pk
new file mode 100644
index 0000000..44ad8a1
--- /dev/null
+++ b/testsuite/poke.pkl/units-diag-3.pk
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+
+defvar n = 10;
+defunit x = 2 + n; /* { dg-error "constant" } */



reply via email to

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