mirror of
https://github.com/kanaka/mal.git
synced 2024-11-11 00:52:44 +03:00
00c3a3c33d
Two changes require approval. * The 'do' special becomes a built-in function similar to first. This small change reduces the complexity of eval. The last evaluation cannot benefit from TCO, but the performance change seems invisible. * read/eval/print acts on each item found in the input string, as if they were enclosed with (do ..). The guide does not specify what should happen to text following the first AST, and this change actually simplifies some things (like dealing with zero AST). The read-string built-in function only returns the first AST, as changing this would be much more intrusive. Other changes seem straightforward. Global: * Ada 2020 target assignments (like +=, but more general). * Use Constant_Indexing aspect for sequences, so that they can be indexed in source code like native arrays. * consistency renamings. 'fn' does not include built-in functions, 'function' does. 'list' does not include vectors, 'sequence' does. Move error handling to a separate package. * This simplifies code everywhere else. * Uncaught expressions now report a stack trace. Types: * Count allocations and deallocations, check that counts match. * Share more code between functions and macros. Core: * Replace the Core.Ns function returning an array with a procedure (The intermediate object was preventing the reference counting code from deallocating some unused objects). * Implement Prn with Pr_Str. Printer: * Change the profile so that the caller spares some allocations. Reader: * Share a single buffer of mal values between all recursions. This significantly reduces the stack footprint. Steps: * Fix implementation name (ada.2) in the startup script. * Let environment variables trigger debugging information.
89 lines
3.4 KiB
Ada
89 lines
3.4 KiB
Ada
with Ada.Strings.Unbounded;
|
|
|
|
with Types.Atoms;
|
|
with Types.Builtins;
|
|
with Types.Fns;
|
|
with Types.Maps;
|
|
with Types.Sequences;
|
|
with Types.Symbols;
|
|
|
|
package Types.Mal is
|
|
|
|
-- A type with a default value for the discriminant is the Ada
|
|
-- equivalent of a C union. It uses a fixed size, and allows
|
|
-- efficient arrays. A class hierarchy would make this impossible,
|
|
-- for little gain.
|
|
-- Native types may seem to consume too much memory, but
|
|
-- 1/ they require no allocation/deallocation.
|
|
-- 2/ the overhead would actually be higher with an intermediate
|
|
-- reference (the size of the pointer plus the size of the native
|
|
-- type, while an union uses the minimum of both and a single
|
|
-- memory area ).
|
|
-- Each instance has the size required for the largest possible
|
|
-- value, so subtypes should attempt to reduce their size when
|
|
-- possible (see Types.Symbols for such a compromise).
|
|
|
|
-- The idea is inspired from the Haskell and OCaml interpreters,
|
|
-- which use a bit to distinguish pointers from integers. Ada
|
|
-- allows to specify the bit position of each component, but
|
|
-- generating such architecture-dependent definitions seems a lot
|
|
-- of work for MAL.
|
|
|
|
-- The Ada tradition is to give explicit names to types, but this
|
|
-- one will be used very often, and almost each package declares
|
|
-- an "use Types;" clause, so Mal.T will do.
|
|
|
|
-- The only problem with a hidden discriminant is that "in out"
|
|
-- parameters cannot be reaffected with a different discriminant.
|
|
-- Eval would be more efficient with "in out" parameters than with
|
|
-- "in" parameters and a result, because lots of reference
|
|
-- counting would be spared, and the implementation would be able
|
|
-- to reuse dynamic memory more efficiently. Environments, and
|
|
-- some list/map operations already attempt such reuse behind the
|
|
-- curtain.
|
|
|
|
-- This would obfuscate the implementation of a functional
|
|
-- language, and require deep changes (the discriminant can be
|
|
-- changed for an in out or access parameter).
|
|
|
|
type T;
|
|
type T_Array;
|
|
type Builtin_Ptr is access function (Args : in T_Array) return T;
|
|
|
|
type T (Kind : Kind_Type := Kind_Nil) is record
|
|
case Kind is
|
|
when Kind_Nil =>
|
|
null;
|
|
when Kind_Boolean =>
|
|
Ada_Boolean : Boolean;
|
|
when Kind_Number =>
|
|
Number : Integer;
|
|
when Kind_Atom =>
|
|
Atom : Atoms.Ptr;
|
|
when Kind_Key =>
|
|
S : Ada.Strings.Unbounded.Unbounded_String;
|
|
when Kind_Symbol =>
|
|
Symbol : Symbols.Ptr;
|
|
when Kind_Sequence =>
|
|
Sequence : Sequences.Ptr;
|
|
when Kind_Map =>
|
|
Map : Maps.Ptr;
|
|
when Kind_Builtin =>
|
|
Builtin : Builtin_Ptr;
|
|
when Kind_Builtin_With_Meta =>
|
|
Builtin_With_Meta : Builtins.Ptr;
|
|
when Kind_Fn | Kind_Macro =>
|
|
Fn : Fns.Ptr;
|
|
end case;
|
|
end record;
|
|
|
|
-- Useful for recursive automatic definition of equality for
|
|
-- composite types like the array type below.
|
|
function "=" (Left, Right : in T) return Boolean with Inline;
|
|
|
|
Nil : constant T := (Kind => Kind_Nil);
|
|
|
|
type T_Array is array (Positive range <>) of T;
|
|
|
|
end Types.Mal;
|