From 79647c59789a6223f3b67a0b120b023eb459af59 Mon Sep 17 00:00:00 2001 From: Alain Prouté Date: Thu, 14 Aug 2014 15:00:45 +0000 Subject: [PATCH] fixed a bug on Opaque(...) and in replace.c --- anubis_dev/compiler/src/a2a.c | 19 ++++++++++++++++--- anubis_dev/compiler/src/compile.c | 18 +++++++++++++----- anubis_dev/compiler/src/interp.c | 11 ++++++++++- anubis_dev/compiler/src/lexer.l | 2 +- anubis_dev/compiler/src/opdef.c | 4 ++-- anubis_dev/compiler/src/replace.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------------------------------------------------------- anubis_dev/library/predefined.anubis | 60 +++++++----------------------------------------------------- anubis_dev/manuals/en/Anubis-doc-1-13.pdf | Bin 449779 -> 0 bytes anubis_dev/manuals/en/Anubis-doc-1-13.tex | 275 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------------- 9 files changed, 399 insertions(+), 230 deletions(-) diff --git a/anubis_dev/compiler/src/a2a.c b/anubis_dev/compiler/src/a2a.c index a9a6def..5f6b340 100644 --- a/anubis_dev/compiler/src/a2a.c +++ b/anubis_dev/compiler/src/a2a.c @@ -118,9 +118,18 @@ static void a2a_type(FILE *fp, } break; - case type_struct_ptr: /* (type_struct_ptr . ) */ + case type_struct_ptr: { - fprintf(fp,"(AnubisType)primitive(_StructPtr(\"%s\"))",name_of_StructPtr[integer_value(cdr(type))]); + if (consp(cdr(type))) + { /* (type_struct_ptr . ) */ + fprintf(fp,"(AnubisType)primitive(_StructPtr(_Opaque(\"%s\")))", + string_content(cdr2(type))); + } + else + { /* (type_struct_ptr . ) */ + fprintf(fp,"(AnubisType)primitive(_StructPtr(\"%s\"))", + name_of_StructPtr[integer_value(cdr(type))]); + } } break; @@ -267,7 +276,10 @@ static char * display_string(char * s) /* count the characters to replace */ for (i = 0; i < l; i++) { - if (s[i] == '\n' || s[i] == '\r' || s[i] == '\"') n++; + if ( s[i] == '\n' + || s[i] == '\r' + || s[i] == '\"' + || s[i] == '\\') n++; } result = (char *)mallocz(l+n+1); j = 0; @@ -276,6 +288,7 @@ static char * display_string(char * s) if (s[i] == '\n') { result[i+j] = '\\'; result[i+j+1] = 'n'; j++; } else if (s[i] == '\r') { result[i+j] = '\\'; result[i+j+1] = 'r'; j++; } else if (s[i] == '\"') { result[i+j] = '\\'; result[i+j+1] = '\"'; j++; } + else if (s[i] == '\\') { result[i+j] = '\\'; result[i+j+1] = '\\'; j++; } else result[i+j] = s[i]; } result[i+j] = 0; diff --git a/anubis_dev/compiler/src/compile.c b/anubis_dev/compiler/src/compile.c index 3a556f1..6db0332 100644 --- a/anubis_dev/compiler/src/compile.c +++ b/anubis_dev/compiler/src/compile.c @@ -1726,14 +1726,22 @@ Expr compile_term(Expr head, Warning: is not significant and should be removed from 'local' */ { - int i = 0; - while (!(car(car(ctxt)) == second(head)) && - !(car(car(ctxt)) == f_micro_ctxt && second(car(ctxt)) == second(head)) + int i = 0; + Expr aux = ctxt; + while (!(car(car(aux)) == second(head)) && + !(car(car(aux)) == f_micro_ctxt && second(car(aux)) == second(head)) ) - { - ctxt = cdr(ctxt); + { + aux = cdr(aux); i++; + if (aux == nil) + { + fprintf(errfile,"The symbol '%s' was not found in the context: ",string_content(second(head))); + debug(ctxt); + anb_exit(1); + } } + //assert(i == integer_value(third(head))); code = mcons3(mcons3(peek,second(head),new_integer(i)), diff --git a/anubis_dev/compiler/src/interp.c b/anubis_dev/compiler/src/interp.c index c1000a8..18883fc 100644 --- a/anubis_dev/compiler/src/interp.c +++ b/anubis_dev/compiler/src/interp.c @@ -2704,7 +2704,12 @@ Expr lambda_interpretations (Expr lc, return nil; } - result = cons(cons(mcons5(closure,lc,mctxt,lctxt,car(aux)),new_env), + result = cons(cons(mcons5(closure, + lc, + mctxt, + lctxt, + car(aux)), + new_env), result); } @@ -2951,6 +2956,8 @@ Expr app_interpretations_1(Expr lc, Expr body = operations[opid].definition; Expr body_type = operations[opid].target_type; + //debug(body); + /* We also need the list of types which are the values (found so far) of the parameters, and the list of original parameters */ @@ -3042,6 +3049,8 @@ Expr app_interpretations_1(Expr lc, body), new_env), result); + + //debug(result); } else #endif diff --git a/anubis_dev/compiler/src/lexer.l b/anubis_dev/compiler/src/lexer.l index 17ecc3c..d5906b1 100644 --- a/anubis_dev/compiler/src/lexer.l +++ b/anubis_dev/compiler/src/lexer.l @@ -1233,7 +1233,7 @@ void end_of_par(void) if (incorrect_pars >= stop_after) anb_exit(1); } errors = 0; - bound_var_count = 0; + //bound_var_count = 0; clean_up_pairs(); more = 0; ext_com_index = 0; diff --git a/anubis_dev/compiler/src/opdef.c b/anubis_dev/compiler/src/opdef.c index 326f8fc..9e76261 100644 --- a/anubis_dev/compiler/src/opdef.c +++ b/anubis_dev/compiler/src/opdef.c @@ -795,8 +795,8 @@ void check_operation(int opid) fprintf(a2a_file," (the type 'AnubisInstance' and related types are defined in section 17 of\n" " 'library/predefined.anubis').\n\n"); fprintf(a2a_file," The purpose of this file is to let you produce anything you want from your program\n" - " (for example, a translation into another language). The root of the module is the\n" - " first element in the list.\n\n"); + " (for example, a translation into another language). The root of the module is\n" + " described by the first paragraph below.\n\n"); collected_type_ids = nil; diff --git a/anubis_dev/compiler/src/replace.c b/anubis_dev/compiler/src/replace.c index 668c293..0655024 100644 --- a/anubis_dev/compiler/src/replace.c +++ b/anubis_dev/compiler/src/replace.c @@ -28,60 +28,104 @@ static Expr fresh_bound_var(void) } - /* Renaming bound variables. - Given an interpretation head, rename_bound all bound variables with fresh system names. + /********************************************************************************** + rename_bound_in_decs takes: + + decs = ((x . T) (y . U) (z . V) ...) declarations of variables + dict = ((y . y1) (u . u1) ...) dictionary for changing the names of some variables + + and returns: + + ((x . T) (y1 . U) (z . V) ...) + + i.e. it replaces the names of declared variables according to the dictionary + */ +static Expr rename_bound_in_decs(Expr decs, + Expr dict) +{ + Expr result = nil; + while (consp(decs)) + { + Expr dec = car(decs); /* dec = (sym . type) */ + Expr new_name = assoc(car(dec),dict); /* get a remplacement name */ + if (new_name == key_not_found) + result = cons(dec,result); /* this entry is unchanged */ + else + result = cons(cons(new_name,cdr(dec)),result); /* this entry is updated: (y . U) becomes (y1 . U) */ + decs = cdr(decs); + } + result = reverse(result); /* put them back in the original order */ + return result; +} + + + + /****************************************************************************************** + Renaming bound variables. + Given an interpretation head, rename_bound renames all bound variables with fresh system names. + + The dictionary 'dict' gives the correspondance between old names and new names: + + dict = ((old_name . new_name) ...) + + where each old name was bound in a surrounding expression (but is free in 'head', and must be + replaced). */ static Expr rename_bound(Expr head, /* the expression within which bound variables must be rename_boundd */ Expr dict) /* a alist giving the correspondance between old names and new names */ { + Expr result = nil; + + //debug(head); + switch(car(head)) { case alt_number: /* (alt_number . ) */ { - return mcons3(car(head),second(head),rename_bound(cdr2(head),dict)); + result = mcons3(car(head),second(head),rename_bound(cdr2(head),dict)); } break; case protect: /* (protect . ) */ { - return mcons3(car(head),second(head),rename_bound(cdr2(head),dict)); + result = mcons3(car(head),second(head),rename_bound(cdr2(head),dict)); } break; case lock: /* (lock . ) */ { - return mcons4(car(head),second(head),third(head),rename_bound(cdr3(head),dict)); + result = mcons4(car(head),second(head),third(head),rename_bound(cdr3(head),dict)); } break; case avm: /* (avm ...) */ { - return head; + result = head; } break; case debug_avm: /* (debug_avm . ) */ { - return mcons3(car(head),second(head),rename_bound(cdr2(head),dict)); + result = mcons3(car(head),second(head),rename_bound(cdr2(head),dict)); } break; case terminal: /* (terminal . ) */ { - return mcons3(car(head),second(head),rename_bound(cdr2(head),dict)); + result = mcons3(car(head),second(head),rename_bound(cdr2(head),dict)); } break; case operation: /* (operation . ) */ { - return head; + result = head; } break; @@ -90,91 +134,118 @@ static Expr rename_bound(Expr head, /* the expression within which bound . ) */ { - return head; /* no need to rename_bound here (names are already unique) */ + result = mcons5(macro, + second(head), + third(head), + forth(head), + rename_bound(cdr4(head),dict)); } break; case string: /* (string . ) */ { - return head; + result = head; } break; case anb_int32: /* (int32 . ) */ { - return head; + result = head; } break; case anb_int_10: /* (anb_int_10 bigit ... bigit) */ { - return head; + result= head; } break; case anb_int_16: /* (anb_int_16 bigit ... bigit) */ { - return head; + result = head; } break; case small_datum: /* (small_datum . ) */ { - return head; + result = head; } break; case word_64: /* (word_64 word1 . word0) */ { - return head; + result = head; } break; case word_128: /* (word_128 word3 word2 word1 . word0) */ { - return head; + result = head; } break; case fpnum: /* (fpnum . ) */ { - return head; + result = head; } break; case local: - /* (local . ) */ + /* (local . ) + + if name has an entry in dict, we must replace the above by: + + (local . ) + */ { Expr new_name = assoc(second(head),dict); if (new_name == key_not_found) - return head; + result = head; else - return mcons4(local,new_name,third(head),cdr3(head)); + result = mcons4(local,new_name,third(head),cdr3(head)); } break; case micro_local: - /* (micro_local . ) */ + /* (micro_local . ) + same method as for 'local' + */ { Expr new_name = assoc(second(head),dict); if (new_name == key_not_found) - return head; + result = head; else - return mcons5(micro_local,new_name,third(head),forth(head),cdr4(head)); + result = mcons5(micro_local,new_name,third(head),forth(head),cdr4(head)); } break; case closure: - /* (closure (f_micro_ctxt fname ftype (sym . type)...) . ) - where is ((sym . type) ...) + /* (closure (f_micro_ctxt fname ftype . ) . ) + where = ((sym . type) ...) + where = ((sym . type) ...) + + declares the arguments of the function. + + The symbols declared in are those which occur in the body of the fonction, + which are not arguments of the function, and which are present in the evaluation + context of the function (i.e. they are not global symbols aka. operation names) + + When renaming bound variables in this interpretation head we must + + (1) replace the symbols in the heads of pairs in using dict. + (2) create a new name for the name of the function if there is one + (3) create new names for the arguments of the function + (4) enlarge dict with the pairs corresponding to the name of the function and the arguments + (5) replace locals in the body of the function using this enlarged dict + */ { /* Here 'fname' is declared as a variable if not nil and @@ -185,27 +256,28 @@ static Expr rename_bound(Expr head, /* the expression within which bound Expr fname = second(mctxt); /* fname */ Expr fname1 = nil; /* new fname (if not nil) */ Expr args1 = nil; /* new */ + Expr dict1 = dict; if (fname != nil) { fname1 = fresh_bound_var(); - dict = cons(cons(fname,fname1),dict); + dict1 = cons(cons(fname,fname1),dict1); } while (consp(args)) { Expr new_name = fresh_bound_var(); args1 = cons(cons(new_name,cdr(car(args))),args1); /* constructing the new */ - dict = cons(cons(car(car(args)),new_name),dict); /* enriching the dictionary */ + dict1 = cons(cons(car(car(args)),new_name),dict1); /* enriching the dictionary */ args = cdr(args); } args1 = reverse(args1); /* put them back in the right order */ - return mcons5(closure, - second(head), - mcons3(f_micro_ctxt,fname1,cdr2(mctxt)), - args1, - rename_bound(cdr4(head),dict)); + result = mcons5(closure, + second(head), + mcons3(f_micro_ctxt,fname1,rename_bound_in_decs(cdr2(mctxt),dict)), + args1, + rename_bound(cdr4(head),dict1)); } break; @@ -219,7 +291,7 @@ static Expr rename_bound(Expr head, /* the expression within which bound f_and_args1 = cons(rename_bound(car(f_and_args),dict),f_and_args1); f_and_args = cdr(f_and_args); } - return mcons3(app, second(head), reverse(f_and_args1)); + result = mcons3(app, second(head), reverse(f_and_args1)); } break; @@ -257,7 +329,7 @@ static Expr rename_bound(Expr head, /* the expression within which bound } cases1 = reverse(cases1); /* put the new cases in the right order */ - return mcons4(cond, + result = mcons4(cond, second(head), rename_bound(third(head),dict), cases1); @@ -283,13 +355,13 @@ static Expr rename_bound(Expr head, /* the expression within which bound resurg = cdr(resurg); } resurg1 = reverse(resurg1); - return mcons7(select_cond_interp, - second(head), - rename_bound(third(head),dict), - forth(head), - cons(car(fifth(head)),resurg1), - rename_bound(sixth(head),dict1), - rename_bound(cdr6(head),dict)); + result = mcons7(select_cond_interp, + second(head), + rename_bound(third(head),dict), + forth(head), + cons(car(fifth(head)),resurg1), + rename_bound(sixth(head),dict1), + rename_bound(cdr6(head),dict)); } break; @@ -297,143 +369,151 @@ static Expr rename_bound(Expr head, /* the expression within which bound /* (with . ) */ { Expr new_name = fresh_bound_var(); - return mcons5(with, - second(head), - new_name, - rename_bound(forth(head),dict), - rename_bound(cdr4(head),cons(cons(third(head),new_name),dict))); + result = mcons5(with, + second(head), + new_name, + rename_bound(forth(head),dict), + rename_bound(cdr4(head),cons(cons(third(head),new_name),dict))); } break; case anb_read: /* (anb_read . ) */ { - return mcons3(car(head),second(head),rename_bound(cdr2(head),dict)); + result = mcons3(car(head),second(head),rename_bound(cdr2(head),dict)); } break; case anb_write: /* (anb_write . ) */ { - return mcons4(anb_write, - second(head), - rename_bound(third(head),dict), - rename_bound(cdr3(head),dict)); + result = mcons4(anb_write, + second(head), + rename_bound(third(head),dict), + rename_bound(cdr3(head),dict)); } break; case anb_exchange: /* (anb_exchange . ) */ { - return mcons4(anb_exchange, - second(head), - rename_bound(third(head),dict), - rename_bound(cdr3(head),dict)); + result = mcons4(anb_exchange, + second(head), + rename_bound(third(head),dict), + rename_bound(cdr3(head),dict)); } break; case wait_for: /* (wait_for . ) */ { - return mcons5(wait_for, - second(head), - rename_bound(third(head),dict), - rename_bound(forth(head),dict), - rename_bound(cdr4(head),dict)); + result = mcons5(wait_for, + second(head), + rename_bound(third(head),dict), + rename_bound(forth(head),dict), + rename_bound(cdr4(head),dict)); } break; case delegate: /* (delegate . ) */ { - return mcons4(delegate, - second(head), - rename_bound(third(head),dict), - rename_bound(cdr3(head),dict)); + result = mcons4(delegate, + second(head), + rename_bound(third(head),dict), + rename_bound(cdr3(head),dict)); } break; case delegatep: /* (delegatep . ) */ { - return mcons5(delegatep, - second(head), - rename_bound(third(head),dict), - rename_bound(forth(head),dict), - rename_bound(cdr4(head),dict)); + result = mcons5(delegatep, + second(head), + rename_bound(third(head),dict), + rename_bound(forth(head),dict), + rename_bound(cdr4(head),dict)); } break; case serialize: /* (serialize . ) */ { - return mcons3(car(head),second(head),rename_bound(cdr2(head),dict)); + result = mcons3(car(head),second(head),rename_bound(cdr2(head),dict)); } break; case tempserialize: /* (tempserialize . ) */ { - return mcons3(car(head),second(head),rename_bound(cdr2(head),dict)); + result = mcons3(car(head),second(head),rename_bound(cdr2(head),dict)); } break; case unserialize: /* (unserialize . ) */ { - return mcons4(unserialize,second(head),third(head),rename_bound(cdr3(head),dict)); + result = mcons4(unserialize,second(head),third(head),rename_bound(cdr3(head),dict)); } break; case tempunserialize: /* (tempunserialize . ) */ { - return mcons4(tempunserialize,second(head),third(head),rename_bound(cdr3(head),dict)); + result = mcons4(tempunserialize,second(head),third(head),rename_bound(cdr3(head),dict)); } break; case bit_width: /* (bit_width . ) */ { - return head; + result = head; } break; case indirect_type: /* (indirect_type . ) */ { - return head; + result = head; } break; case vcopy: /* (vcopy n . v) */ { - return mcons3(vcopy,rename_bound(second(head),dict),rename_bound(cdr2(head),dict)); + result = mcons3(vcopy,rename_bound(second(head),dict),rename_bound(cdr2(head),dict)); } break; case type_desc_interp: /* (type_desc_interp . ) */ { - return head; + result = head; } break; case byte_array: /* (byte_array ...) */ { - return head; + result = head; } break; default: assert(0); } + + //debug(result); + + return result; } - /* The replacement auxiliary function */ + /******************************************************************************************************** + + The replacement auxiliary function + + */ static Expr replace_aux(Expr head, /* where bound variables are already renamed */ Expr alist) /* ((sym . value) ...) replace sym by value ... */ diff --git a/anubis_dev/library/predefined.anubis b/anubis_dev/library/predefined.anubis index b25ad3f..f689231 100644 --- a/anubis_dev/library/predefined.anubis +++ b/anubis_dev/library/predefined.anubis @@ -5542,10 +5542,6 @@ public type AnubisType: List(AnubisType) operands). // or: Result(Error,$T) // but also: Bool (with an empty list of operands) -public type AnubisArg: // used for components of alternatives, resurgent symbols and arguments of functions - arg (AnubisType type, - String name). - public type AnubisComponent: comp (AnubisType type), // anonymous component comp (AnubisType type, @@ -5564,6 +5560,10 @@ public type AnubisAlternative: public type AnubisTerm:... // defined below +public type AnubisArg: + arg (AnubisType type, + String name). + public type AnubisCase: // case in a conditional _case (String name, List(AnubisArg) resurgent_symbols, @@ -5623,57 +5623,11 @@ public type AnubisScope: private, public. - We also represent implementations of types as they are computed by the Anubis compiler. - -public type AnubisCompImplementation: // Implementation of a component (of an alternative) - comp (Int component_type_id, // unique id of type instance of component - Int offset, // offset of component in the memory segment - Int width). // width of component (see explanations below). - - Note: small types may have only small alternatives - mixed types may have small and mixed alternatives - large types may have only large alternatives - - For a small alternative and represent: - - number of bits below argument bit field (including index field) - width of bit field (in bits) - - For a mixed alternative: - - number of bytes above reference counter of data segment - width of fields in bytes - - For a large alternative: - - number of bytes above index field in data segment - width of field in bytes - - -public type AnubisAltImplementation: // implementation of an alternative - small_alt (List(AnubisCompImplementation) components), - mixed_alt (List(AnubisCompImplementation) components), - large_alt (List(AnubisCompImplementation) components). - -public type AnubisImplementation: // Implementation of a type as computed by the Anubis compiler - primitive_type (AnubisPrimitiveType), - // the implementation of primitive types is decribed in the documentation - small_type (Int nalt, // number of alternatives - Int index_bit_width, // bit width for storing the indexes of alternatives - List(AnubisAltImplementation) alternatives), - mixed_type (Int nalt, // number of alternatives - Int index_bit_width, // bit width for storing the indexes of alternatives - List(AnubisAltImplementation) alternatives), - large_type (Int nalt, // number of alternatives - Int index_bit_width, // bit width for storing the indexes of alternatives - List(AnubisAltImplementation) alternatives), - functional_type. public type AnubisTypeInstance: - type (Int id, // unique id of instance of type - AnubisType the_type, // description of type - Maybe(List(AnubisAlternative)) alternatives, // alternatives if it is a sum type - AnubisImplementation implementation). // implementation of type as computed by the by Anubis compiler + type (Int id, // unique id of instance of type + AnubisType the_type, // description of type + Maybe(List(AnubisAlternative)) alternatives). // alternatives if it is a sum type public type AnubisDatumInstance: constructor (Int id, // unique id of constructor diff --git a/anubis_dev/manuals/en/Anubis-doc-1-13.pdf b/anubis_dev/manuals/en/Anubis-doc-1-13.pdf index 59c0d44..cbfe1b7 100644 Binary files a/anubis_dev/manuals/en/Anubis-doc-1-13.pdf and b/anubis_dev/manuals/en/Anubis-doc-1-13.pdf differ diff --git a/anubis_dev/manuals/en/Anubis-doc-1-13.tex b/anubis_dev/manuals/en/Anubis-doc-1-13.tex index c19ae2a..b05e98d 100644 --- a/anubis_dev/manuals/en/Anubis-doc-1-13.tex +++ b/anubis_dev/manuals/en/Anubis-doc-1-13.tex @@ -2837,7 +2837,7 @@ how to use a formater. The subsequent sections explain how to write down a forma In these explanations we assume that the target language is the language C. We also assume of course that you have an Anubis project containing a ``global'' paragraph whose name is \code{my\_program}, and that -you have already produced the file \code{my\_program.a2a} by using the option \code{.a2a} of the +you have already produced the file \code{my\_program.a2a} by using the option \code{-a2a} of the Anubis compiler. In order to produce the file \code{my\_program.c} containing your project written in the C language, @@ -2848,19 +2848,21 @@ create an Anubis file containing this~: read my_program.a2a use the data produced by the compiler read a2a/C/formater.anubis use the formater for the language C - Produce the module which will produce your C source file: + Define the module which will produce your C source file: global define One - make_my_C_source + make_my_C_source // chose this name freely ( List(String) args // not used ) = - format(my_program). + format("my_program.c", + my_program_types, + my_program_data). and execute it: execute anbexec make_my_C_source \end{verbatim} } -That's all~! +That's all~! The file \fn{my\_program.c} is created and contains the desired C source. This will not fail with the C language because the C formater is able to translate all of Anubis, but this may fail for another formater (which maybe needs to be enhanced, but of course, enhancing a formater requires @@ -2888,8 +2890,7 @@ As an example, here is the definition of \code{AnubisTypeInstance}~: public type AnubisTypeInstance: type (Int id, AnubisType the_type, - Maybe(List(AnubisAlternative)) alternatives, - AnubisImplementation implementation). + Maybe(List(AnubisAlternative)) alternatives). \end{verbatim} } This shows how a datum of type \code{AnubisTypeInstance} decribes an instance of an Anubis type definition. @@ -2903,9 +2904,6 @@ type \code{AnubisType}. \item The component \code{alternatives} may have the value \code{failure}, meaning that the type is not defined by a paragraph. It is either a primitive type or a functional type. If the value of this component is \code{success(l)}, then \code{l} describes the alternatives of the type definition. See below for the details. -\item The component \code{implementation} describes how the Anubis compiler implements the type. This is more technical, -but may be useful for translating the type description into a type definition in another language. For example, -this is used by the C formater. The details of this description are given below in section \myref{sec:implementation}. \end{liste} For example, we have the following paragraph in \fn{library/a2a/example.a2a}~: {\color{codecolor} @@ -2917,12 +2915,7 @@ define AnubisTypeInstance a2at_5 = [comp((AnubisType)primitive(_String))]), alt("alt2", [comp((AnubisType)primitive(_Int),"x"), - comp((AnubisType)primitive(_String),"s")])]), - mixed_type((Int)002, - (Int)002, - [mixed_alt([comp((Int)0,(Int)0,(Int)4)]), - mixed_alt([comp((Int)3,(Int)0,(Int)4), - comp((Int)0,(Int)4,(Int)4)])])). + comp((AnubisType)primitive(_String),"s")])])). \end{verbatim} } which describes the type definition~: @@ -2958,94 +2951,206 @@ public type AnubisDatumInstance: \begin{liste} \item The alternative \code{constructor} is used for describing constructors of defined types. In our example, the type \code{ExampleType} has two constuctors whose names are \code{alt1} and \code{alt2}. -\end{liste} - -\suc - - -\subsubsection{Instances of Anubis paragraphs} -An Anubis source file is mainly (as you already know) a sequence of paragraphs. Some of these -paragraphs are ``schemas'', i.e. contain types parameters (such as \code{\$T}). ``Instanciating -a schema'' means replacing the type parameters by actual types. For example, the definition of \code{List} is -a schema whose parameter represents the type of elements in the lists. This schema can be instanciated -as \code{List(String)} or as \code{List(Int)} or as \code{List(T)} where \code{T} is any type. -Similarly, the function \code{length} computing the length of a list is a schema, since it can compute -the length of a list whose elements have any possible type. - -A type parameter cannot be implemented (i.e. it cannot receive an actual representation method in computer memory) since we don't know -anything about this type. Only instances of types can be implemented. Similarly, only instances of functions (and -other data) can be compiled. A module file (\code{.adm}) contains only compilations of instances of data. - -What the \code{.a2a} file contains is an intermediary representation of the module, precisely the state -of the module when it is already checked as a correct program, and eveything is appropriately instanciated, -but not yet transformed into a sequence -of Anubis virtual machine instructions. Furthermore, these instances are presented in the \code{.a2a} file in the form -of Anubis data, hence easily usable by way of an Anubis program. In order to let you understand precisely -what I mean by ``in the form of Anubis data'', here is an example. The following is the content of the file -\fn{library/a2a/example.anubis}~: +Again, each datum instance is identified by a unique integer. Here is the paragraph describing \code{alt1} +in \fn{library/a2a/example.a2a}~: +{\color{codecolor} +\begin{verbatim} + /* constructor 'alt1', type: ((String) -> ExampleType) */ +define AnubisDatumInstance a2ad_6 = + constructor(6, + "alt1", + [(AnubisType)primitive(_String)], + instance((Int)5,"ExampleType",[])). +\end{verbatim} +} +The file \code{example.a2a} does not contain a description of \code{alt2}. This is normal, since the ``global'' +paragraph in \fn{library/a2a/example.anubis}~: {\color{codecolor} \begin{verbatim} - A simple type: - -type ExampleType: - alt1(String), - alt2(Int x, String s). - - A simple (secondary) module: - global define ExampleType example = alt1("Hello"). \end{verbatim} } -We compile this file with the option \code{-a2a} and we obtain the file -\fn{library/a2a/example.a2a} which contains the unique paragraph (plus initial comments -not reproduced here)~: +does not make use of the constructor \code{alt2}. + +\item The alternative \code{primitive} describes a primitive function. The only informations are the name and the type. +The identifier may change from one version of Anubis to another one, because it depends on the design of the +file \fn{predef.anubis}. However, it is sure that not two distinct primitive can have the same name and the same +type, and these data are less likely to change with versions of Anubis. Hence, these informations should preferably be used +by a formater. Anyway, if the file \fn{predef.anubis} is enhanced, it is likely that the formaters must be enhanced +accordingly. + +\item The alternative \code{datum} describes an instance of a definition of datum. The informations on such an instance +are the following~: + \begin{liste} + \item The unique identifier \code{id}. + \item The name of the datum defined. + \item The path of the file where it is defined (this informations may become a comment in the source + file of the target language). + \item The line at which it is defined. + \item The scope of the definition, which can be either \code{private} or \code{public}. Notice that + there is no information such as \code{macro} of \code{inline}. This is because since we are + describing only instances of paragraphs, all references to a macro or an inline function are + already replaced by the bodies of these definition. Hence, in the \code{.a2a} file (and also + of course in the \code{.adm} file, the macros and inline functions have ``vanished''. + \item The target type of the definition instance. + \item The list of argument declarations, each one in the form \code{arg(\sconcept{type},\sconcept{name})}. + \item The description of the (instanciated) body of the definition. + \end{liste} + +\end{liste} + + +\subsubsection{Description of types} +The following types are used for describing Anubis types~: {\color{codecolor} \begin{verbatim} -public define NonEmptyList(AnubisInstance) example = - [ - /* 'example' in '.../library/a2a/example.anubis' at line 10 */ - (AnubisInstance)datum(1309, - "example", - ".../library/a2a/example.anubis", - 10, - _apply(_operation("alt1",1307), - [_string("Hello")])), - - /* type 'ExampleType' */ - (AnubisInstance)type(5, - instance(178,"ExampleType",[]), - success([alt("alt1", - [comp(primitive(_String))]), - alt("alt2", - [comp(primitive(_Int),"x"), - comp(primitive(_String),"s")])]), - [mixed_type]) - ]. +public type AnubisType:... + +public type AnubisPrimitiveType: + _ByteArray, + _Float, + _Int, + _Listener, + _MVar (AnubisType), + _RStream, + _RWStream, + _String, + _StructPtr (String name), + _Var (AnubisType), + _WStream. + +public type AnubisType: + parameter (String name), + primitive (AnubisPrimitiveType), + functional (List(AnubisType) sources, + AnubisType target), + instance (Int id, + String name, + List(AnubisType) operands). + +public type AnubisComponent: + comp (AnubisType type), + comp (AnubisType type, + String name). + +public type AnubisAlternative: + alt (String name, + List(AnubisComponent) components). \end{verbatim} } -As you see, \code{example} is defined here as a list of two ``Anubis Instances'', i.e. instances of paragraphs. -Notice that the number of instances in the \code{.a2a} file has nothing to do -with the number of paragraphs in the source file, and this for many reasons. First of all, the \code{.a2a} file does not -represent the source file, but the module defined by the ``global'' paragraph. In particular, if the compiler encounters -several ``global'' paragraphs, it produces several \code{.a2a} files. Also, in an \code{.a2a} file, you can find -instances of paragraphs located in other files than the file the name of which is on the Anubis compiler command line, -because of the \code{read} and \code{transmit} keywords. Finally, a single paragraph may produce several instances -in a single module, hence several instances in a single \code{.a2a} file. -Nevertheless, what you see above is that the \code{.a2a} file presents instances in the form which is the easiest -for doing something with them, namely as Anubis text. -Now, in order to decipher the above example, we need to discuss the types used in \code{.a2a} files. +\subsubsection{Description of data} +The following types are used for describing Anubis terms~: +{\color{codecolor} +\begin{verbatim} +public type AnubisTerm:... + +public type AnubisArg: + arg (AnubisType type, + String name). + +public type AnubisCase: + _case (String name, + List(AnubisArg) resurgent_symbols, + AnubisTerm body). + +public type AnubisTerm: + _apply (AnubisTerm function, + List(AnubisTerm) arguments), + _byte_array (ByteArray content), + _cond (AnubisTerm test, + List(AnubisCase) cases), + _integer (Int value), + _delegate (AnubisTerm priority, + AnubisTerm delegated, + AnubisTerm body), + _float (Float value), + _function (List(AnubisArg) arguments, + Maybe(String) function_name, + AnubisTerm body), + _micro_symbol(String name), + _of_type (AnubisType type, + AnubisTerm term), + _operation (String name, + Int id), + _protect (AnubisTerm protected), + _read (AnubisTerm v), + _select_cond (AnubisTerm test, + Int index_of_selected, + AnubisCase selected_case, + AnubisTerm default), + _serialize (AnubisTerm term), + _small_datum (AnubisType type, + Int value), + _string (String value), + _symbol (String name), + _type_desc (AnubisType type), + _unserialize (AnubisType type, + AnubisTerm byte_array), + _wait_for (AnubisTerm condition, + AnubisTerm body), + _with (String symbol, + AnubisTerm value, + AnubisTerm body), + _write (AnubisTerm v, + AnubisTerm value). +\end{verbatim} +} + + + -\subsubsection{Implementations of types}\mylabel{sec:implementation} -\suc \subsubsection{Primitives} \suc + +\subsubsection{Designing a formater} +If you want to create a new formater, the easiest is probably to begin by having a look +at the C formater in the file \fn{library/a2a/C/formater.anubis}. In parallel, +you should read the present section. + +From now on, we assume that the name of the module (and of the \code{.a2a} file) is \code{my\_program}. We also +assume in these explanations that the target language is the language C, but the principles are valid for +any target language. +Since we manipulate only instance of types and data, we will simply say ``type'' instead of ``instance of type'', +and similarly for data. + +In the file \code{my\_program.a2a} there are only two public paragraphs, and they are defined like this~: +{\color{codecolor} +\begin{verbatim} +public define List(AnubisTypeInstance) my_program_types = + [ + ... + ]. + +public define List(AnubisDatumInstance) my_program_data = + [ + ... + ]. +\end{verbatim} +} +The first one gives the list of the representations of all types, and the second one the list +of the representations of all data. These two lists, together with the name you want to give to the C file, + are given as arguments to the function \code{format} which must be +of type~: +\begin{ccode} + (String,List(AnubisTypeInstance),List(AnubisDatumInstance)) -> One +\end{ccode} +The role of format is to create a new file named \code{my\_program.c} and to write into it the C translation +of the data found in the two lists. + +The first thing to do is to translate type descriptions into types of the target language. This is of course possible +for C, but maybe more problematic for an untyped language. In this last case, you must decide for a format +of data, which is mainly the same thing as defining a type, except that the compiler of the target will not check +these types. They will be checked only at run time. + + + \section{The Anubis Library} \subsection{Overview} -- libgit2 0.21.4