1
1
mirror of https://github.com/kanaka/mal.git synced 2024-10-05 18:08:55 +03:00
mal/impls/ada/types.ads
Nicolas Boulenguez 033892777a Merge eval-ast and macro expansion into EVAL, add DEBUG-EVAL
See issue #587.
* Merge eval-ast and eval into a single conditional.
* Expand macros during the apply phase, removing lots of duplicate
  tests, and increasing the overall consistency by allowing the macro
  to be computed instead of referenced by name (`((defmacro! cond
  (...)))` is currently illegal for example).
* Print "EVAL: $ast" at the top of EVAL if DEBUG-EVAL exists in the
  MAL environment.
* Remove macroexpand and quasiquoteexpand special forms.
* Use pattern-matching style in process/step*.txt.

Unresolved issues:
c.2: unable to reproduce with gcc 11.12.0.
elm: the directory is unchanged.
groovy: sometimes fail, but not on each rebuild.
nasm: fails some new soft tests, but the issue is unreproducible when
  running the interpreter manually.
objpascal: unreproducible with fpc 3.2.2.
ocaml: unreproducible with 4.11.1.
perl6: unreproducible with rakudo 2021.09.

Unrelated changes:
Reduce diff betweens steps.
Prevent defmacro! from mutating functions: c forth logo miniMAL vb.
dart: fix recent errors and warnings
ocaml: remove metadata from symbols.

Improve the logo implementation.
Encapsulate all representation in types.lg and env.lg, unwrap numbers.
Replace some manual iterations with logo control structures.
Reduce the diff between steps.
Use native iteration in env_get and env_map
Rewrite the reader with less temporary strings.
Reduce the number of temporary lists (for example, reverse iteration
with butlast requires O(n^2) allocations).
It seems possible to remove a few exceptions: GC settings
(Dockerfile), NO_SELF_HOSTING (IMPLS.yml) and step5_EXCLUDES
(Makefile.impls) .
2024-08-05 11:40:49 -05:00

439 lines
13 KiB
Ada

-- This started out as a simple public variant record.
-- Then smart pointers were added. They were part of the Mal_Type and
-- were required to be public because of the dependencies and
-- how the variant record was public. Not very Ada-like.
-- The third version bites the bullet and delares Mal_Type as tagged.
-- Smart pointers are an OO version in a separate package.
-- The Doubly_Linked_Lists have been replaced with a tree-like list instead...
-- The tree-like list has been replaced with a singly linked list. Sigh.
-- WARNING! This code contains:
-- Recursive data structures.
-- Object-based smart pointers.
-- Object-oriented code.
-- And strong-typing!
-- Chris M Moore 25/03/2015
with Ada.Strings.Unbounded;
with Smart_Pointers;
with Envs;
package Types is
-- Some simple types. Not supposed to use the standard types directly.
subtype Mal_Float is Float;
subtype Mal_Integer is Integer;
subtype Mal_String is String;
-- Start off with the top-level abstract type.
subtype Mal_Handle is Smart_Pointers.Smart_Pointer;
function "=" (A, B : Mal_Handle) return Mal_Handle;
function "=" (A, B : Mal_Handle) return Boolean;
type Sym_Types is (Nil, Bool, Int, Floating, Str, Sym, Atom, Node,
List, Func, Lambda, Error);
type Mal_Type is abstract new Smart_Pointers.Base_Class with private;
function Sym_Type (T : Mal_Type) return Sym_Types is abstract;
function Get_Meta (T : Mal_Type) return Mal_Handle;
procedure Set_Meta (T : in out Mal_Type'Class; SP : Mal_Handle);
function Copy (M : Mal_Handle) return Mal_Handle;
function To_String (T : Mal_Type'Class; Print_Readably : Boolean := True)
return Mal_String;
type Mal_Ptr is access all Mal_Type'Class;
-- A helper function that just view converts the smart pointer to
-- a Mal_Type'Class pointer.
function Deref (S : Mal_Handle) return Mal_Ptr;
-- A helper function to detect null smart pointers.
function Is_Null (S : Mal_Handle) return Boolean;
-- Derived types. All boilerplate from here.
type Nil_Mal_Type is new Mal_Type with private;
function New_Nil_Mal_Type return Mal_Handle;
overriding function Sym_Type (T : Nil_Mal_Type) return Sym_Types;
type Int_Mal_Type is new Mal_Type with private;
function New_Int_Mal_Type (Int : Mal_Integer) return Mal_Handle;
overriding function Sym_Type (T : Int_Mal_Type) return Sym_Types;
function Get_Int_Val (T : Int_Mal_Type) return Mal_Integer;
type Int_Ptr is access all Int_Mal_Type;
function Deref_Int (SP : Mal_Handle) return Int_Ptr;
type Float_Mal_Type is new Mal_Type with private;
function New_Float_Mal_Type (Floating : Mal_Float) return Mal_Handle;
overriding function Sym_Type (T : Float_Mal_Type) return Sym_Types;
function Get_Float_Val (T : Float_Mal_Type) return Mal_Float;
type Float_Ptr is access all Float_Mal_Type;
function Deref_Float (SP : Mal_Handle) return Float_Ptr;
type Bool_Mal_Type is new Mal_Type with private;
function New_Bool_Mal_Type (Bool : Boolean) return Mal_Handle;
overriding function Sym_Type (T : Bool_Mal_Type) return Sym_Types;
function Get_Bool (T : Bool_Mal_Type) return Boolean;
type Bool_Ptr is access all Bool_Mal_Type;
function Deref_Bool (SP : Mal_Handle) return Bool_Ptr;
type String_Mal_Type is new Mal_Type with private;
function New_String_Mal_Type (Str : Mal_String) return Mal_Handle;
overriding function Sym_Type (T : String_Mal_Type) return Sym_Types;
function Get_String (T : String_Mal_Type) return Mal_String;
type String_Ptr is access all String_Mal_Type;
function Deref_String (SP : Mal_Handle) return String_Ptr;
type Symbol_Mal_Type is new Mal_Type with private;
function New_Symbol_Mal_Type (Str : Mal_String) return Mal_Handle;
overriding function Sym_Type (T : Symbol_Mal_Type) return Sym_Types;
function Get_Sym (T : Symbol_Mal_Type) return Mal_String;
type Sym_Ptr is access all Symbol_Mal_Type;
function Deref_Sym (S : Mal_Handle) return Sym_Ptr;
type Atom_Mal_Type is new Mal_Type with private;
function New_Atom_Mal_Type (MH : Mal_Handle) return Mal_Handle;
overriding function Sym_Type (T : Atom_Mal_Type) return Sym_Types;
function Get_Atom (T : Atom_Mal_Type) return Mal_Handle;
procedure Set_Atom (T : in out Atom_Mal_Type; New_Val : Mal_Handle);
type Atom_Ptr is access all Atom_Mal_Type;
function Deref_Atom (S : Mal_Handle) return Atom_Ptr;
type Error_Mal_Type is new Mal_Type with private;
function New_Error_Mal_Type (Str : Mal_String) return Mal_Handle;
overriding function Sym_Type (T : Error_Mal_Type) return Sym_Types;
-- Lists.
type List_Types is (List_List, Vector_List, Hashed_List);
function Opening (LT : List_Types) return Character;
function Closing (LT : List_Types) return Character;
type List_Mal_Type is new Mal_Type with private;
function "=" (A, B : List_Mal_Type) return Boolean;
function New_List_Mal_Type
(List_Type : List_Types;
The_First_Node : Mal_Handle := Smart_Pointers.Null_Smart_Pointer)
return Mal_Handle;
function New_List_Mal_Type
(The_List : List_Mal_Type)
return Mal_Handle;
type Handle_Lists is array (Positive range <>) of Mal_Handle;
-- Make a new list of the form: (Handle_List(1), Handle_List(2)...)
function Make_New_List (Handle_List : Handle_Lists) return Mal_Handle;
overriding function Sym_Type (T : List_Mal_Type) return Sym_Types;
function Get_List_Type (L : List_Mal_Type) return List_Types;
function Prepend (Op : Mal_Handle; To_List : List_Mal_Type)
return Mal_Handle;
procedure Append (To_List : in out List_Mal_Type; Op : Mal_Handle);
function Length (L : List_Mal_Type) return Natural;
function Nth (L : List_Mal_Type; N : Natural) return Mal_Handle;
procedure Add_Defs (Defs : List_Mal_Type; Env : Envs.Env_Handle);
-- Get the first item in the list:
function Car (L : List_Mal_Type) return Mal_Handle;
-- Get the rest of the list (second item onwards)
function Cdr (L : List_Mal_Type) return Mal_Handle;
type Func_Access is access
function (Elem : Mal_Handle)
return Mal_Handle;
function Map
(Func_Ptr : Func_Access;
L : List_Mal_Type)
return Mal_Handle;
type Binary_Func_Access is access
function (A, B : Mal_Handle)
return Mal_Handle;
function Reduce
(Func_Ptr : Binary_Func_Access;
L : List_Mal_Type)
return Mal_Handle;
function Is_Null (L : List_Mal_Type) return Boolean;
function Null_List (L : List_Types) return List_Mal_Type;
function Pr_Str (T : List_Mal_Type; Print_Readably : Boolean := True)
return Mal_String;
function Cat_Str (T : List_Mal_Type; Print_Readably : Boolean := True)
return Mal_String;
function Concat (Rest_Handle : List_Mal_Type)
return Types.Mal_Handle; -- a new list
-- Duplicate copies the list (logically). This is to allow concatenation,
-- The result is always a List_List.
function Duplicate (The_List : List_Mal_Type) return Mal_Handle;
type List_Ptr is access all List_Mal_Type;
function Deref_List (SP : Mal_Handle) return List_Ptr;
type List_Class_Ptr is access all List_Mal_Type'Class;
function Deref_List_Class (SP : Mal_Handle) return List_Class_Ptr;
type Func_Mal_Type is new Mal_Type with private;
type Builtin_Func is access
function (MH : Mal_Handle) return Mal_Handle;
function New_Func_Mal_Type (Str : Mal_String; F : Builtin_Func)
return Mal_Handle;
overriding function Sym_Type (T : Func_Mal_Type) return Sym_Types;
function Get_Func_Name (T : Func_Mal_Type) return Mal_String;
function Call_Func
(FMT : Func_Mal_Type; Rest_List : Mal_Handle)
return Mal_Handle;
type Func_Ptr is access all Func_Mal_Type;
function Deref_Func (S : Mal_Handle) return Func_Ptr;
type Lambda_Mal_Type is new Mal_Type with private;
function New_Lambda_Mal_Type
(Params : Mal_Handle; Expr : Mal_Handle; Env : Envs.Env_Handle)
return Mal_Handle;
overriding function Sym_Type (T : Lambda_Mal_Type) return Sym_Types;
function Get_Env (L : Lambda_Mal_Type) return Envs.Env_Handle;
procedure Set_Env (L : in out Lambda_Mal_Type; Env : Envs.Env_Handle);
function Get_Params (L : Lambda_Mal_Type) return Mal_Handle;
function Get_Expr (L : Lambda_Mal_Type) return Mal_Handle;
function Get_Is_Macro (L : Lambda_Mal_Type) return Boolean;
procedure Set_Is_Macro (L : in out Lambda_Mal_Type; B : Boolean);
function Apply
(L : Lambda_Mal_Type;
Param_List : Mal_Handle) return Mal_Handle;
type Lambda_Ptr is access all Lambda_Mal_Type;
function Deref_Lambda (SP : Mal_Handle) return Lambda_Ptr;
generic
with function Int_Op (A, B : Mal_Integer) return Mal_Integer;
with function Float_Op (A, B : Mal_Float) return Mal_Float;
function Arith_Op (A, B : Mal_Handle) return Mal_Handle;
generic
with function Int_Rel_Op (A, B : Mal_Integer) return Boolean;
with function Float_Rel_Op (A, B : Mal_Float) return Boolean;
function Rel_Op (A, B : Mal_Handle) return Mal_Handle;
Runtime_Exception : exception;
Mal_Exception : exception; -- So tempting to call this Mal_Function but...
Mal_Exception_Value : Mal_Handle; -- Used by mal's throw command
private
type Mal_Type is abstract new Smart_Pointers.Base_Class with record
Meta : Mal_Handle;
end record;
-- Not allowed to be abstract and private. RM 3.9.3(10)
-- So if you call this it'll just raise an exception.
function To_Str (T : Mal_Type; Print_Readably : Boolean := True)
return Mal_String;
type Nil_Mal_Type is new Mal_Type with null record;
overriding function To_Str (T : Nil_Mal_Type; Print_Readably : Boolean := True)
return Mal_String;
type Int_Mal_Type is new Mal_Type with record
Int_Val : Mal_Integer;
end record;
overriding function To_Str (T : Int_Mal_Type; Print_Readably : Boolean := True)
return Mal_String;
type Float_Mal_Type is new Mal_Type with record
Float_Val : Mal_Float;
end record;
overriding function To_Str (T : Float_Mal_Type; Print_Readably : Boolean := True)
return Mal_String;
type Bool_Mal_Type is new Mal_Type with record
Bool_Val : Boolean;
end record;
overriding function To_Str (T : Bool_Mal_Type; Print_Readably : Boolean := True)
return Mal_String;
type String_Mal_Type is new Mal_Type with record
The_String : Ada.Strings.Unbounded.Unbounded_String;
end record;
overriding function To_Str (T : String_Mal_Type; Print_Readably : Boolean := True)
return Mal_String;
type Symbol_Mal_Type is new Mal_Type with record
The_Symbol : Ada.Strings.Unbounded.Unbounded_String;
end record;
overriding function To_Str (T : Symbol_Mal_Type; Print_Readably : Boolean := True)
return Mal_String;
type Atom_Mal_Type is new Mal_Type with record
The_Atom : Mal_Handle;
end record;
overriding function To_Str (T : Atom_Mal_Type; Print_Readably : Boolean := True)
return Mal_String;
type Func_Mal_Type is new Mal_Type with record
Func_Name : Ada.Strings.Unbounded.Unbounded_String;
Func_P : Builtin_Func;
end record;
overriding function To_Str (T : Func_Mal_Type; Print_Readably : Boolean := True)
return Mal_String;
type Error_Mal_Type is new Mal_Type with record
Error_Msg : Ada.Strings.Unbounded.Unbounded_String;
end record;
overriding function To_Str (T : Error_Mal_Type; Print_Readably : Boolean := True)
return Mal_String;
-- Nodes have to be a differnt type from a List;
-- otherwise how do you represent a list within a list?
type Node_Mal_Type is new Mal_Type with record
Data : Mal_Handle;
Next : Mal_Handle; -- This is always a Node_Mal_Type handle
end record;
function New_Node_Mal_Type
(Data : Mal_Handle;
Next : Mal_Handle := Smart_Pointers.Null_Smart_Pointer)
return Mal_Handle;
overriding function Sym_Type (T : Node_Mal_Type) return Sym_Types;
overriding function To_Str
(T : Node_Mal_Type; Print_Readably : Boolean := True)
return Mal_String;
type Node_Ptr is access all Node_Mal_Type;
function Deref_Node (SP : Mal_Handle) return Node_Ptr;
type List_Mal_Type is new Mal_Type with record
List_Type : List_Types;
The_List : Mal_Handle;
Last_Elem : Mal_Handle;
end record;
overriding function To_Str
(T : List_Mal_Type; Print_Readably : Boolean := True)
return Mal_String;
type Container_Cursor is tagged record
The_Node : Node_Ptr := null;
end record;
type Lambda_Mal_Type is new Mal_Type with record
Params, Expr : Mal_Handle;
Env : Envs.Env_Handle;
Is_Macro : Boolean;
end record;
overriding function To_Str
(T : Lambda_Mal_Type; Print_Readably : Boolean := True)
return Mal_String;
end Types;