forked from dllaurence/Nil
-
Notifications
You must be signed in to change notification settings - Fork 0
/
exp.llh
163 lines (124 loc) · 5.31 KB
/
exp.llh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#ifndef EXP_LLH
#define EXP_LLH
;**********************************************************************
; exp.llh
;
; Public declarations for the Expression module.
;
; Copyright 2009-2010 by Dustin Laurence. Distributed under the terms of
; the LGPLv3.
;
;**********************************************************************
#include "nil.llh"
;FIXME: quite a bit of this header should be private
; Fundamental types
; The fundamental handle type by which we manipulate expressions.
; Everything in Nil is an expression, implemented (usually) as a pointer
; to an object (of the low-level malloc() sort, not the Smalltalk or
; even C++ sort). The pointer is represented as an integer because exp
; will be storing type tags in the low-order bits, and need to
; manipulate the bits to know the type before we know how to manipulate
; the pointer.
; Naming convention note; this isn't nil_exp because I don't think
; lisp has or needs an explicit name for this type--*EVERYTHING* is this
; type, always.
%Exp = type %Word
; This is our representation, though we don't actually need it explicit
; It would have been better to use this anyway, but I did not.
;%nil_symbol = type %c_char
%nil_cell = type {%Exp, %Exp}
; Internal representation--a primitive is a native function over
; expressions. The word is the required number of arguments so
; the interpreter can do some sanity checking, and the string is
; a printing format. The bit flag is whether the primitive is magic
; (i.e. handles its own argument evaluation like a macro)
%PrimFn = type %Exp (%Exp, %Exp)
%nil_primitive = type {%PrimFn*, %Word, %c_char*, i1}
; Tag field type values.
; This and the *_TAG constants are the only places where the code
; assumes the size of the tag field, so it can be extended as needed
; simply by changing the type here.
#define TAG_BITS 3
%Tag = type i3
#define MAX_TAG 7
; For now, I sometimes change these values randomly to ensure the code
; is clean and not depending on particular bit patterns. They should
; fit insize a %Tag type (or they'll be silently wrapped), but otherwise
; are arbitrary.
#define SYMBOL_TAG 1
#define CELL_TAG 2
#define EXCEPTION_TAG 3
#define PRIMITIVE_TAG 4
; We define Nil as the null symbol (or at least not as the null CELL,
; which is an obvious choice as nil is the empty list) instead of the
; null cell because it makes testing for a non-null cell a single
; comparison. The code *does* assume this (most especially it assumes
; NIL does not have CELL_TAG).
#define NIL_VALUE SYMBOL_TAG
; Low-level manipulation of the tags embedded in the low-order bits.
; FIXME: these trivial functions should *always* be inlined
declare NILCC %Tag @GetTag(%Exp %exp)
declare NILCC i1 @TagIs(%Exp %exp, %Tag %tag)
declare NILCC i1 @TagIsNot(%Exp %exp, %Tag %tag)
declare NILCC i1 @SameTag(%Exp %lhs, %Exp %rhs)
declare NILCC %Exp @ClearTag(%Exp %exp)
declare NILCC %Exp @AddTag(%Exp %exp, %Tag %tag)
declare NILCC %Exp @SetTag(%Exp %exp, %Tag %tag)
declare NILCC i1 @TagIsClear(%Exp %exp)
declare NILCC %Word @ShiftOutTag(%Exp %exp)
declare NILCC %Word @SignedShiftOutTag(%Exp %exp)
declare NILCC %Exp @ShiftInTag(%Word %word)
; Conversions
; Symbol
declare NILCC %Exp @str2Exp(%c_char* %str)
declare NILCC %c_char* @Exp2str(%Exp %exp)
; List
declare NILCC %Exp @nil_cell2Exp(%nil_cell* %cell)
declare NILCC %nil_cell* @Exp2nil_cell(%Exp %exp)
; Primitive
declare NILCC %Exp @nil_primitive2Exp(%nil_primitive* %prim)
declare NILCC %nil_primitive* @Exp2nil_primitive(%Exp %exp)
; Exception
declare NILCC %Exp @Exception2Exp(%Word %code)
declare NILCC %Word @Exp2Exception(%Exp %exp)
; The "seven primitive operators" of Paul Graham's paper, plus
; internal forms
; #1 -- quote
; No internal form
; #2 -- atom
declare NILCC i1 @IsAtom(%Exp %exp) ; Internal form
; #3 -- eq (see notes on whether this is precisely Graham's eq
; Internal form
declare NILCC i1 @Eq(%Exp %lhs, %Exp %rhs)
declare NILCC i1 @NotEq(%Exp %lhs, %Exp %rhs)
; #4 -- car
declare NILCC %Exp @Car(%Exp %exp)
; #5 -- cdr
declare NILCC %Exp @Cdr(%Exp %exp)
; #6 -- cons
declare NILCC %Exp @Cons(%Exp %car, %Exp %cdr)
; #7 -- cond
; No internal form
; Other tests
declare NILCC i1 @IsSymbol(%Exp %exp)
declare NILCC i1 @IsCell(%Exp %exp)
declare NILCC i1 @IsList(%Exp %exp)
declare NILCC i1 @IsPrimitive(%Exp %exp)
declare NILCC i1 @IsException(%Exp %exp)
declare NILCC i1 @NotException(%Exp %exp)
declare NILCC i1 @IsNil(%Exp %exp)
declare NILCC i1 @NotNil(%Exp %exp)
; Other symbol manipulations
; Symbol creation
; The interfaces are somewhat inconsistent, but convenient
declare NILCC %Exp @NewSymbol(%c_char* %name)
declare NILCC %nil_cell* @NewCell()
declare NILCC %Exp @NewPrimitive(%PrimFn*, %Word %argCount,
%c_char* %printForm, i1 %magic)
; Lists
declare NILCC %Word @Len(%Exp %list)
; Exceptions
declare NILCC %c_char* @ExceptionMsg(%Word %code)
; Expression I/O
declare NILCC void @PrintExp(%Exp %exp)
#endif