-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkeywords.py
102 lines (73 loc) · 2.31 KB
/
keywords.py
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
'''
It would be nice if this module didn't need to import anything,
since it defines (part of) the syntax of the language, and that
and that seems like something that should be completely abstract.
But macros make it possible to alter the syntax at run-time,
meaning that keyword dispatch has to be cognizant of the mutable
state of the machine!
###
Is it "cheating" to include keyword_dispatch? It would be trivial
to unroll it into a big ugly list of branch-if statements, so it
doesn't really add any expressive power. Still, to mollify the
skeptic, keyword_dispatch can be imagined as a piece of specialized
hardware. Further, it can be stipulated that its use is relatively
expensive, thereby gaining some advantage for analyze-interpretation.
'''
from env import is_macro
from stats import dispatch_stats
DEFINE_KEYS = 'define', 'def'
ASS_KEYS = 'set!', 'ass!'
LAMBDA_KEYS = 'lambda', 'λ', 'fun'
IF_KEYS = 'if',
BEGIN_KEYS = 'begin', 'progn'
QUOTE_KEYS = 'quote',
QUASIQUOTE_KEYS = 'quasiquote', 'qsq'
UNQUOTE_KEYS = 'unquote', 'unq'
SPLICE_KEYS = 'splice', 'spl'
DEFMACRO_KEYS = 'defmacro', 'defmac'
###
@dispatch_stats
def keyword_dispatch(expr):
if is_var(expr):
return 'EVAL_VAR'
if is_num(expr):
return 'EVAL_NUM'
# else
tag, *_ = expr
keyword_groups = {
DEFINE_KEYS : 'EVAL_DEF',
ASS_KEYS : 'EVAL_ASS',
LAMBDA_KEYS : 'EVAL_LAMBDA',
IF_KEYS : 'EVAL_IF',
BEGIN_KEYS : 'EVAL_BEGIN',
QUOTE_KEYS : 'EVAL_QUOTE',
QUASIQUOTE_KEYS : 'EVAL_QUASIQUOTE',
DEFMACRO_KEYS : 'EVAL_DEFMACRO',
}
for group in keyword_groups:
if tag in group:
return keyword_groups[group]
if is_macro(tag):
return 'EVAL_MACRO'
# default
return 'EVAL_FUNC'
###
def is_num(exp):
try:
return isinstance(int(exp), int)
except (ValueError, TypeError):
return False
def is_var(exp):
return isinstance(exp, str)
def is_simple(expr):
return is_num(expr) or is_var(expr) or expr == []
###
def has_tag(expr, tag_keys):
try:
return expr[0] in tag_keys
except (TypeError, IndexError):
return False
def is_unquoted(expr):
return has_tag(expr, UNQUOTE_KEYS)
def is_splice(expr):
return has_tag(expr, SPLICE_KEYS)