Browse Source

- new util to check the understanding of c3 mro
- update structs
- small documentation on how inheritance works under the hood

tcheukueppo 2 năm trước cách đây
mục cha
commit
7b353a80be
6 tập tin đã thay đổi với 263 bổ sung49 xóa
  1. 71 0
      docs/inheritance.md
  2. 1 1
      docs/maat.md
  3. 4 5
      docs/types/Array.md
  4. 4 6
      src/ma_conf.h
  5. 80 37
      src/ma_obj.h
  6. 103 0
      utils/c3-mro.pl

+ 71 - 0
docs/inheritance.md

@@ -0,0 +1,71 @@
+# Classes
+
+## Overview
+
+## Class Artichecture
+
+## Inheritances
+
+Maat uses C3 mro as resolution order for resolving method calls, method
+resolution is done during compilation which makes Maat pretty fast at
+execution.
+
+```
+
+                (f(D))        (f(Z))
+                 D ──────────► Z
+                 ▲
+                 │
+                 │
+                 │
+
+                (f(B))
+        ┌──────►  B ────────► E (f(E))
+        │                    ▲
+ (f(A)) A                    │
+        │                    │
+        │       (f(C))       │
+        └──────► C ──────────┘
+                 │
+                 │
+               │       (f(M))     (f(K))
+                 └──────► M ───────► K
+```
+
+The above diagram shows the inheritance relationships between the classes
+`A`, `B`, `C`, `D`, `E`, `M`, `K`, and `Z`. For example we have class `A`
+which directly inherits from class `B` and `C` and indirectly inherits from
+class `K`.
+
+### Problem
+
+We wish to resolve a method `f` when calling it from an object which is an
+instance of `A`.
+
+### Solution
+
+Let `X` be a class belonging to the set of classes
+`{A, B, C, D, E, M, K, Z}`, `X` **may** have its own implementation of `f`
+denoted `f(X)`. By applying the C3 method resolution algorithm at
+compilation, we use the divide and conquer approach to perform a breadth-first
+traversal on the inheritance tree of `X`, this yields an array which contains
+contains in C3 order pointers to all the implementations of `f` we found.
+This array is recorded as the value stored at the entry of `f` in the method
+hash table of X, the first element of this arrays is the top level method that
+is going to be called during an `f` call by an object instance of `X`. The
+rest of the elements are used to handle `__SUPER__` calls, especially when
+they are chained across multiple `f` calls.
+
+Let function R(X:f) denotes the `f` method resolution of class `X` that
+returns the array we were talking of.
+
+We have the following:
+
+```
+```
+
+For an object instance of A, the following is true
+
+```
+...
+```

+ 1 - 1
docs/maat.md

@@ -410,7 +410,6 @@ var array = [1, 2, 3, 4, 5]
 Maat has ... builtin objects, types are objects and objects are types, check
 Maat has ... builtin objects, types are objects and objects are types, check
 details on each types here.
 details on each types here.
 
 
-- [`Any`](./types/Any.md)
 - [`Bool`](./types/Bool.md)
 - [`Bool`](./types/Bool.md)
 - [`Num`](./types/Num.md)
 - [`Num`](./types/Num.md)
 - [`Str`](./types/Str.md)
 - [`Str`](./types/Str.md)
@@ -426,6 +425,7 @@ details on each types here.
 - [`GFun`](./types/GFun.md)
 - [`GFun`](./types/GFun.md)
 - [`Regex`](./types/Regex.md)
 - [`Regex`](./types/Regex.md)
 - [`Ma`](./types/Ma.md)
 - [`Ma`](./types/Ma.md)
+- [`Co`](./types/Co.md)
 - [`Work`](./types/Work.md)
 - [`Work`](./types/Work.md)
 - [`Chan`](./types/Chan.md)
 - [`Chan`](./types/Chan.md)
 - [`Socket`](./types/Socket.md)
 - [`Socket`](./types/Socket.md)

+ 4 - 5
docs/types/Array.md

@@ -6,13 +6,12 @@
 
 
 ```
 ```
 -- Yep, we have multiple ways of declaring an Array object
 -- Yep, we have multiple ways of declaring an Array object
-var x = [qw(one two three four)]
-var a = qa<liza madjou monthe>
+var x = [ w(one two three four) ]
 var b = ["kueppo", "cyrus", "christ"]
 var b = ["kueppo", "cyrus", "christ"]
-var c = Array.new(2, 3, "four", qa<5 6>)
+var c = Array.new(2, 3, "four", [w<5 6>])
 
 
-.say for a.lmap(.split) -- qa{l i z a m a d j o u m o n t h e}
-.say for a.map(.split)  -- qa{l i z a}, qa{m a d j o u}, qa{m o n t h e}
+.say for a.lmap(.split) -- [ w{l i z a m a d j o u m o n t h e} ]
+.say for a.map(.split)  -- [ [ w{l i z a} ], [ w{m a d j o u} ], [ w{m o n t h e} ] ]
 ```
 ```
 
 
 ## Methods
 ## Methods

+ 4 - 6
src/ma_conf.h

@@ -65,13 +65,12 @@
  * Maat can co-exist within 'X:\\Program Files\Maat\'
  * Maat can co-exist within 'X:\\Program Files\Maat\'
  */
  */
 #if !defined(MA_CLIB_DEFAULT_PATH)
 #if !defined(MA_CLIB_DEFAULT_PATH)
-#define MA_CLIB_DEFAULT_PATH  "!\\" MA_VERSION "\\lib\\",
-#endif
 
 
-#if !defined(MA_MTLIB_DEFAULT_PATH)
+#define MA_CLIB_DEFAULT_PATH  "!\\" MA_VERSION "\\lib\\",
 #define MA_MTLIB_DEFAULT_PATH \
 #define MA_MTLIB_DEFAULT_PATH \
    "!\\" MA_VERSION "\\share\\", \
    "!\\" MA_VERSION "\\share\\", \
    "!\\" MA_VERSION "\\maat\\",
    "!\\" MA_VERSION "\\maat\\",
+
 #endif
 #endif
 
 
 #define MA_DIRSEP  "\\"
 #define MA_DIRSEP  "\\"
@@ -81,13 +80,12 @@
 #define MA_LOCAL_ROOT  "/usr/local/"
 #define MA_LOCAL_ROOT  "/usr/local/"
 
 
 #if !defined(MA_CLIB_DEFAULT_PATH)
 #if !defined(MA_CLIB_DEFAULT_PATH)
-#define MA_CLIB_DEFAULT_PATH  MA_LOCAL_ROOT "lib/maat/" MA_VERSION "/",
-#endif
 
 
-#if !defined(MA_MTLIB_DEFAULT_PATH)
+#define MA_CLIB_DEFAULT_PATH  MA_LOCAL_ROOT "lib/maat/" MA_VERSION "/",
 #define MA_MTLIB_DEFAULT_PATH \
 #define MA_MTLIB_DEFAULT_PATH \
    MA_LOCAL_ROOT "share/maat/" MA_VERSION "/", \
    MA_LOCAL_ROOT "share/maat/" MA_VERSION "/", \
    "/usr/share/maat/" MA_VERSION "/",
    "/usr/share/maat/" MA_VERSION "/",
+
 #endif
 #endif
 
 
 #define MA_DIRSEP  "/"
 #define MA_DIRSEP  "/"

+ 80 - 37
src/ma_obj.h

@@ -14,7 +14,7 @@
  * specific to `#if` body of the MA_NAN_TAGGING check.
  * specific to `#if` body of the MA_NAN_TAGGING check.
  */
  */
 
 
-/* Vary type 't' with the variant bits 'v', see Value */
+/* Vary type 't' with variant bits 'v', see Value */
 #define vary(t, v)  ((t) | (v << 5))
 #define vary(t, v)  ((t) | (v << 5))
 
 
 #define with_variant(v)      ((v)->type & 0x7F)
 #define with_variant(v)      ((v)->type & 0x7F)
@@ -25,7 +25,7 @@
 /* Get top level value type of 'v' */
 /* Get top level value type of 'v' */
 #define vtype(v)  with_variant(v)
 #define vtype(v)  with_variant(v)
 
 
-/* value 'o' is an object and get its object type */
+/* Value 'o' is an object and get its object type */
 #define otype(o)  with_variant(as_obj(v))
 #define otype(o)  with_variant(as_obj(v))
 
 
 /* Get profound type of 'v': dig into 'v' if it's an object */
 /* Get profound type of 'v': dig into 'v' if it's an object */
@@ -68,7 +68,7 @@ typedef struct {
       struct Header *obj;
       struct Header *obj;
       Num n;
       Num n;
       CFunc f;
       CFunc f;
-      void *cdata;
+      void *p;
    } val;
    } val;
 } Value;
 } Value;
 
 
@@ -77,15 +77,15 @@ typedef struct {
 #define set_valo(v, o)      set_val(v, o, (o)->type)
 #define set_valo(v, o)      set_val(v, o, (o)->type)
 
 
 /*
 /*
- * For objects, copy by reference v2 into v1 while
- * for non objects (numbers, etc), copy by value.
+ * For objects, copy by reference 'v2' into 'v1' while for other type
+ * of values like numbers, booleans, and function/void pointers, do a
+ * copy by value.
  */
  */
 #define copy(v1, v2)  set_val(v1, v2->val, v2->type)
 #define copy(v1, v2)  set_val(v1, v2->val, v2->type)
 
 
 /*
 /*
- * All the possible standard types of a value, look! V_TYPE_OBJ
- * is also one. A value 'v' is an object if the MSB of its $type
- * is 1.
+ * Defines all the possible standard types of a value, V_TYPE_OBJ is
+ * also a value. A value 'v' is an object if the MSB of its $type is 1.
  */
  */
 #define V_TYPE_NIL    0
 #define V_TYPE_NIL    0
 #define V_TYPE_BOOL   1
 #define V_TYPE_BOOL   1
@@ -102,7 +102,7 @@ typedef struct {
 #define is_cfunc(v)  check_type(v, V_TYPE_CFUNC)
 #define is_cfunc(v)  check_type(v, V_TYPE_CFUNC)
 #define is_cdata(v)  check_type(v, V_TYPE_CDATA)
 #define is_cdata(v)  check_type(v, V_TYPE_CDATA)
 
 
-/* Check if a value is collectable */
+/* Check if value 'v' is collectable */
 #define is_ctb(v)  is_obj(v)
 #define is_ctb(v)  is_obj(v)
 
 
 #define as_bool(v)   (is_true(v))
 #define as_bool(v)   (is_true(v))
@@ -171,23 +171,25 @@ typedef struct Header {
 #define o_check_type(v, t)  is_obj(v) && check_type(v, t)
 #define o_check_type(v, t)  is_obj(v) && check_type(v, t)
 
 
 /* Defining of all base objects */
 /* Defining of all base objects */
-#define O_TYPE_CLASS   5    
+#define O_TYPE_CLASS   5   /* variant: O_TYPEV_CCLASS */
 #define O_TYPE_STR     6    
 #define O_TYPE_STR     6    
 #define O_TYPE_RANGE   7    
 #define O_TYPE_RANGE   7    
 #define O_TYPE_ARRAY   8   /* variants: O_TYPEV_SET, O_TYPEV_MSET, O_TYPEV_LIST */
 #define O_TYPE_ARRAY   8   /* variants: O_TYPEV_SET, O_TYPEV_MSET, O_TYPEV_LIST */
 #define O_TYPE_MAP     9   /* variants: O_TYPEV_BAG, O_TYPEV_MBAG */
 #define O_TYPE_MAP     9   /* variants: O_TYPEV_BAG, O_TYPEV_MBAG */
-#define O_TYPE_FUN     10  /* variants: O_TYPEV_CLOSURE */
-#define O_TYPE_CO     12  /* variants: O_TYPEV_MA, O_TYPEV_WORK */
-#define O_TYPE_RBQ     13  /* variants: O_TYPEV_CHAN, O_TYPEV_SCHEDQ */
-#define O_TYPE_REGEX   14
-#define O_TYPE_SOCKET  15
-#define O_TYPE_PIPE    16
-#define O_TYPE_FILE    17
-#define O_TYPE_DIR     18
-#define O_TYPE_PROC    19
-#define O_TYPE_SYS     20
-#define O_TYPE_DATE    21
+#define O_TYPE_FUN     10  /* variant:  O_TYPEV_CLOSURE */
+#define O_TYPE_MA      11  /* variants: O_TYPEV_CO, O_TYPEV_WORK */
+#define O_TYPE_RBQ     12  /* variants: O_TYPEV_CHAN, O_TYPEV_SCHEDQ */
+#define O_TYPE_REGEX   13
+#define O_TYPE_SOCKET  14
+#define O_TYPE_PIPE    15
+#define O_TYPE_FILE    16
+#define O_TYPE_DIR     17
+#define O_TYPE_PROC    18
+#define O_TYPE_SYS     19
+#define O_TYPE_DATE    20
+#define O_TYPE_PKG     21
 #define O_TYPE_TERM    22
 #define O_TYPE_TERM    22
+
 #define O_DEADKEY      31  /* */
 #define O_DEADKEY      31  /* */
 
 
 /* A Check macro on 'v' for each object type */
 /* A Check macro on 'v' for each object type */
@@ -211,7 +213,16 @@ typedef struct Header {
 /* Test if the value 'v' is an object variant of variant type 't' */
 /* Test if the value 'v' is an object variant of variant type 't' */
 #define o_check_vartype(v,t)  is_obj(v) && check_vartype(v,t)
 #define o_check_vartype(v,t)  is_obj(v) && check_vartype(v,t)
 
 
-/* Here are variants of some base objects */
+/* Here are variants of some standard objects */
+
+/*
+ * Cclass--a special way of extending Maat code with C/C++, here
+ * we store references to C/C++ functions as methods and structs
+ * as attributes.
+ */
+#define O_TYPEV_CCLASS  vary(O_TYPE_CLASS, 1)
+
+#define is_cclass(v)  o_check_vartype(v, O_TYPEV_CCLASS)
 
 
 /* Immutable and mutable bags */
 /* Immutable and mutable bags */
 #define O_TYPEV_BAG   vary(O_TYPE_MAP, 1)
 #define O_TYPEV_BAG   vary(O_TYPE_MAP, 1)
@@ -234,9 +245,9 @@ typedef struct Header {
 
 
 #define is_closure(v)  o_check_vartype(v, O_TYPEV_CLOSURE)
 #define is_closure(v)  o_check_vartype(v, O_TYPEV_CLOSURE)
 
 
-#define O_TYPEV_MA    vary(O_TYPE_CMA, 1)
-#define O_TYPEV_GFUN  vary(O_TYPE_CMA, 1)
-#define O_TYPEV_MA    vary(O_TYPE_CMA, 1)
+/* Two other concurrency models: Coroutine, Work */
+#define O_TYPEV_CO    vary(O_TYPE_CMA, 1)
+#define O_TYPEV_WORK  vary(O_TYPE_CMA, 2)
 
 
 /* A threadsafe Channel and Scheduler queue */
 /* A threadsafe Channel and Scheduler queue */
 #define O_TYPEV_CHAN    vary(O_TYPE_RBQ, 1)
 #define O_TYPEV_CHAN    vary(O_TYPE_RBQ, 1)
@@ -246,50 +257,81 @@ typedef struct Header {
 #define is_schedq(v)  o_check_type(v, O_TYPEV_SCHEDQ)
 #define is_schedq(v)  o_check_type(v, O_TYPEV_SCHEDQ)
 
 
 /*
 /*
- * What? utf8 string object
- * $str: utf8 encoded string itself
+ * What? string object
+ * $str: utf-8 encoded string itself
  * $hash: hash value of $str
  * $hash: hash value of $str
  * $rlen: real length of $str
  * $rlen: real length of $str
  * $len: user-percieved length of $str
  * $len: user-percieved length of $str
  */
  */
+
 typedef struct {
 typedef struct {
    Header obj;
    Header obj;
-   Uint hash;
+   unsigned int hash;
    size_t rlen;
    size_t rlen;
    size_t len;
    size_t len;
    Byte str[1];
    Byte str[1];
 } Str;
 } Str;
 
 
 /*
 /*
- * What? Range object x..y
- * $x: the start (inclusive)
- * $y: the end (inclusive)
+ * What? Range object [x..y] (inclusive)
+ * $x: the start
+ * $y: and the end
  */
  */
+
 typedef struct {
 typedef struct {
    Header obj;
    Header obj;
-   Num x, y;
+   Num x;
+   Num y;
 } Range;
 } Range;
 
 
+/*
+ */
+
 typedef struct {
 typedef struct {
    Header obj;
    Header obj;
 } Map;
 } Map;
 
 
 /*
 /*
- * $super: class' superclasses (C3 mro)
+ * $is: class' superclasses (Maat implements C3 mro)
  * $name: class name
  * $name: class name
- * $nfields: number of fields
+ * $n: number of fields(Class)/cdatas(Cclass)
  * $methods: a Map for methods
  * $methods: a Map for methods
  */
  */
+
+#define x ...
+
 typedef struct Class {
 typedef struct Class {
    Header obj;
    Header obj;
-   struct Class *super[1];
    Str *name;
    Str *name;
-   Ubyte nfields;
-   Map *methods[1];
+   union {
+      struct Class *is[1];
+      Value *cdatas;
+   } sc;
+   Ubyte n;
+   Map *methods;
 } Class;
 } Class;
 
 
+/*
+ * What? Instance of a class
+ * $fields: (C)?class' attributes/cdata
+ */
+typedef struct {
+   Header obj;
+   Value *fields;
+} Instance;
+
+typedef struct Ma {
+
+} Ma;
+
+typedef struct {
+   Ma ma;
+   
+} Work;
+
 /*
 /*
  */
  */
+
 typedef struct {
 typedef struct {
    Header obj;
    Header obj;
    //...
    //...
@@ -297,6 +339,7 @@ typedef struct {
 
 
 /*
 /*
  */
  */
+
 typedef struct Upvalue {
 typedef struct Upvalue {
    Header obj;
    Header obj;
    Value *to;
    Value *to;

+ 103 - 0
utils/c3-mro.pl

@@ -0,0 +1,103 @@
+#!/usr/bin/env perl
+
+# Abstract: Check if c3 mro is well understood.
+# License: AGL, see LICENSE file for copyright and license details.
+#
+# General structure of a small DSL for defining classes with their
+# methods and inheritance relationships. This program parses the
+# DSL following __DATA__ and perform series of tests of c3 method
+# resolution with validation done with the help of Perl's c3 mro.
+#
+# CLASS_NAME: METHOD_NAME
+# SUBCLASS_NAME -> ( SUPERCLASS_NAME ... ) : METHOD_NAME ...
+#
+# Example:
+# O: meth1 meth2 meth3
+# A -> (O) : meth2
+# B -> (O) : meth1
+# C -> (A B) : meth2
+# 
+# The above example defines a section, sections are separated by
+# the token '###'. Sections are tested individually.
+
+use strict;
+use warnings;
+use feature qw(say);
+
+use Data::Dumper;
+
+sub parse_class_defs_section {
+   my $def_str = shift;
+   my $defs;
+
+   while ($def_str =~ /\G ([A-Z]) (?: \h+ -> \h+ \( (?<s>[A-Z](?:\h++[A-Z])*) \) )? (?: \h+ : \h+ (?<m>\w+(?:\h++\w++)*) )? \s* /gx) {
+      $defs->{$1} = undef;
+      if (defined $+{s}) {
+         my @supers = split " ", $+{s};
+         my @undefs = grep { !exists $defs->{$_} } @supers;
+         die "undefined class(es): [@undefs]\n" if @undefs;
+         $defs->{$1}{s} = [@supers];
+      }
+      $defs->{$1}{m} = [ split " ", $+{m} ] if defined($+{m});
+   }
+
+   return $defs;
+}
+
+sub parse_class_defs_sections {
+   my $data = shift;
+   my $sections;
+
+   push @$sections, parse_class_defs_section($1) while $data =~ /\G\s*(.+?)(?:###|\z)/gs;
+   return $sections;
+}
+
+sub gen_classdefs_perl_code {
+   my $sections = shift;
+   my ($section_codes, $perl_code);
+
+   foreach my $section (@$sections) {
+      $perl_code .= "\n\nuse feature qw(say);\n\n";
+      foreach my $class (sort keys %$section) {
+         my $class_info = $section->{$class};
+
+         $perl_code .= "package $class {\n\n";
+         $perl_code .= "\tuse parent -norequire qw(@{$class_info->{s}});\n\n" if exists $class_info->{s};
+         if (exists $class_info->{m}) {
+            foreach my $method (@{$class_info->{m}}) {
+               my $name = $method =~ s/@$//r;
+
+               $perl_code .= "\tsub $name { say 'A::$name'; " . ( $method =~ /@$/ ? "'$class'->next::method(); }" : "; }" );
+               $perl_code .= "\n\n";
+               $perl_code .= "}\n\n";
+            }
+         }
+      }
+      push @$section_codes, [ $section, $perl_code ];
+   }
+
+   return $section_codes;
+}
+
+sub c3_linearize {
+   my $section = shift;
+   my %linearized;
+
+   foreach my $class (sort keys %$section) {
+
+   }
+}
+
+{
+   local $/;
+   my $sections = parse_class_defs_sections(<DATA>);
+   say Dumper gen_perl_code($sections);
+}
+
+__DATA__
+O : meth1 meth2 meth3
+A -> (O) : meth2
+B -> (O) : meth1
+C -> (A B) : meth2
+###
+O