Remove `Macro` type internally, replace `macro?` with `operator?`
Chris Pressey
4 years ago
11 | 11 | the macro itself as the first argument to the macro.) |
12 | 12 | The Robin definitions of macros in the standard library |
13 | 13 | such as `let` and `list` have been rewritten this way. |
14 | * The object that a `macro` form evaluates to is no | |
15 | longer called a "macro". It is an "operator". There | |
16 | there are other ways to obtain an operator than applying | |
17 | a `macro` form (for instance there have always been | |
18 | intrinsic operators; it's not fair to call them "macros".) | |
14 | 19 | |
15 | 20 | For the reference implementation, |
16 | 21 | |
17 | 22 | * Fixed recent import changes which prevented it from |
18 | 23 | running under Hugs. |
24 | * The `Macro` type of expressions has been removed, | |
25 | and `Builtin` renamed `Operator`. | |
19 | 26 | |
20 | 27 | Robin 0.7 |
21 | 28 | --------- |
4 | 4 | mkdir -p pkg |
5 | 5 | |
6 | 6 | cat stdlib/abort.robin stdlib/equal-p.robin stdlib/eval.robin stdlib/head.robin \ |
7 | stdlib/if.robin stdlib/list-p.robin stdlib/macro-p.robin stdlib/macro.robin \ | |
7 | stdlib/if.robin stdlib/list-p.robin stdlib/operator-p.robin stdlib/macro.robin \ | |
8 | 8 | stdlib/number-p.robin stdlib/prepend.robin stdlib/recover.robin stdlib/sign.robin \ |
9 | 9 | stdlib/subtract.robin stdlib/symbol-p.robin stdlib/tail.robin \ |
10 | 10 | > pkg/intrinsics.robin |
313 | 313 | |
314 | 314 | ### Macros ### |
315 | 315 | |
316 | TODO rewrite this section | |
317 | ||
316 | 318 | A macro is a term which, in an environment, describes how to |
317 | 319 | translate one S-expression to another. |
318 | 320 | |
343 | 345 | |
344 | 346 | Macros evaluate to themselves. |
345 | 347 | |
346 | Macros are represented as the S-expression expansion of their | |
347 | implementation. | |
348 | Operators are represented as an opaque descriptor (TODO this should be the | |
349 | metadata of the operator.) | |
348 | 350 | |
349 | 351 | | (macro (args env) args) |
350 | = (macro (args env) args) | |
351 | ||
352 | Macros can be applied, and that is the typical use of them. | |
352 | = <macro> | |
353 | ||
354 | Operators can be applied, and that is the typical use of them. | |
353 | 355 | |
354 | 356 | | ((macro (args env) args) 1) |
355 | 357 | = (1) |
38 | 38 | -- |
39 | 39 | -- Evaluating a list means we must make several evaluations. We |
40 | 40 | -- evaluate the head to obtain something to apply (which must be a |
41 | -- macro or intrinsic.) We then apply the body of the macro, | |
42 | -- passing it the tail of the list. | |
41 | -- "builtin".) We then apply the "builtin", passing it the tail of the list. | |
43 | 42 | -- |
44 | 43 | |
45 | 44 | eval env (List (applierExpr:actuals)) cc = |
46 | 45 | eval env applierExpr (\applier -> |
47 | 46 | case applier of |
48 | m@(Macro _ _ body) -> | |
49 | eval (makeMacroEnv env (List actuals) m) body cc | |
50 | b@(Builtin _ fun) -> | |
47 | Builtin _ fun -> | |
51 | 48 | fun env (List actuals) cc |
52 | 49 | other -> |
53 | 50 | errMsg "inapplicable-object" other) |
67 | 64 | errMsg msg term = |
68 | 65 | Abort (List [(Symbol msg), term]) |
69 | 66 | |
70 | makeMacroEnv :: Env -> Expr -> Expr -> Env | |
71 | makeMacroEnv env actuals m@(Macro closedEnv argList _) = | |
67 | makeMacro :: Expr -> Expr -> Expr -> Evaluable | |
68 | makeMacro defineTimeEnv formals body = | |
69 | \callTimeEnv actuals cc -> | |
70 | let | |
71 | env = makeMacroEnv callTimeEnv actuals defineTimeEnv formals | |
72 | in | |
73 | eval env body cc | |
74 | ||
75 | makeMacroEnv callTimeEnv actuals defineTimeEnv argList = | |
72 | 76 | let |
73 | 77 | (List [(Symbol argFormal), (Symbol envFormal)]) = argList |
74 | newEnv' = insert argFormal actuals closedEnv | |
75 | newEnv'' = insert envFormal env newEnv' | |
78 | newEnv' = insert argFormal actuals defineTimeEnv | |
79 | newEnv'' = insert envFormal callTimeEnv newEnv' | |
76 | 80 | in |
77 | 81 | newEnv'' |
82 | ||
78 | 83 | |
79 | 84 | -- |
80 | 85 | -- Assertions |
89 | 94 | assertBoolean env = assert env (isBoolean) "expected-boolean" |
90 | 95 | assertList env = assert env (isList) "expected-list" |
91 | 96 | assertNumber env = assert env (isNumber) "expected-number" |
92 | assertMacro env = assert env (isMacro) "expected-macro" | |
97 | assertOperator env = assert env (isOperator) "expected-operator" |
19 | 19 | data Expr = Symbol String |
20 | 20 | | Boolean Bool |
21 | 21 | | Number Int32 |
22 | | Macro Expr Expr Expr -- the 1st Expr is actually an Env | |
23 | 22 | | Builtin String Evaluable |
24 | 23 | | List [Expr] |
25 | 24 | | Abort Expr |
28 | 27 | (Symbol x) == (Symbol y) = x == y |
29 | 28 | (Boolean x) == (Boolean y) = x == y |
30 | 29 | (Number x) == (Number y) = x == y |
31 | (Macro e1 a1 b1) == (Macro e2 a2 b2) = e1 == e2 && a1 == a2 && b1 == b2 | |
32 | 30 | (Builtin x _) == (Builtin y _) = x == y |
33 | 31 | (List x) == (List y) = x == y |
34 | 32 | (Abort x) == (Abort y) = x == y |
39 | 37 | show (Boolean True) = "#t" |
40 | 38 | show (Boolean False) = "#f" |
41 | 39 | show (Number n) = show n |
42 | show (Macro env args body) = ("(macro " ++ (show args) ++ | |
43 | " " ++ (show body) ++ ")") | |
44 | 40 | show (Builtin name _) = name |
45 | 41 | show (Abort e) = "(abort " ++ (show e) ++ ")" |
46 | 42 | show (List exprs) = "(" ++ (showl exprs) ++ ")" where |
71 | 67 | isList (List _) = True |
72 | 68 | isList _ = False |
73 | 69 | |
74 | isMacro (Macro _ _ _) = True | |
75 | isMacro (Builtin _ _) = True | |
76 | isMacro _ = False | |
77 | ||
78 | 70 | isAbort (Abort _) = True |
79 | 71 | isAbort _ = False |
72 | ||
73 | isOperator (Builtin _ _) = True | |
74 | isOperator _ = False |
41 | 41 | |
42 | 42 | symbolP = predP isSymbol |
43 | 43 | listP = predP isList |
44 | macroP = predP isMacro | |
44 | operatorP = predP isOperator | |
45 | 45 | numberP = predP isNumber |
46 | 46 | |
47 | 47 | subtract :: Evaluable |
79 | 79 | |
80 | 80 | macro :: Evaluable |
81 | 81 | macro env (List [args@(List [(Symbol argsS), (Symbol envS)]), body]) cc = |
82 | cc $ Macro env args body | |
82 | cc $ Builtin "<macro>" $ makeMacro env args body | |
83 | 83 | macro env other cc = errMsg "illegal-arguments" other |
84 | 84 | |
85 | 85 | abort :: Evaluable |
105 | 105 | ("prepend", prepend), |
106 | 106 | ("list?", listP), |
107 | 107 | ("symbol?", symbolP), |
108 | ("macro?", macroP), | |
108 | ("operator?",operatorP), | |
109 | 109 | ("number?", numberP), |
110 | 110 | ("equal?", equalP), |
111 | 111 | ("subtract", Language.Robin.Intrinsics.subtract), |
33 | 33 | let n' = n `div` (m + 1) |
34 | 34 | oneof [ |
35 | 35 | Abort <$> (arbExpr n'), |
36 | List <$> (arbExprList n'), | |
37 | Macro <$> (arbExpr n') <*> (arbExpr n') <*> (arbExpr n') | |
36 | List <$> (arbExprList n') | |
37 | -- TODO Operator ?? | |
38 | 38 | ] |
39 | 39 | |
40 | 40 | arbExprList :: Int -> Gen [Expr] |
0 | ;'<<SPEC' | |
1 | ||
2 | ### `macro?` ### | |
3 | ||
4 | -> Tests for functionality "Evaluate core Robin Expression" | |
5 | ||
6 | `macro?` evaluates its argument, then evaluates to `#t` if it is a macro, | |
7 | or `#f` if it is not. | |
8 | ||
9 | | (macro? (macro (args env) args)) | |
10 | = #t | |
11 | ||
12 | Intrinsic macros are macros. | |
13 | ||
14 | | (macro? macro) | |
15 | = #t | |
16 | ||
17 | Literal symbols are not macros, even if they're the name of one. | |
18 | ||
19 | | (macro? ((macro (args env) (head args)) macro)) | |
20 | = #f | |
21 | ||
22 | Numbers are not macros. | |
23 | ||
24 | | (macro? 5) | |
25 | = #f | |
26 | ||
27 | The argument to `macro?` may (naturally) be any type, but there must be | |
28 | exactly one argument. | |
29 | ||
30 | | (macro? macro macro) | |
31 | ? abort (illegal-arguments (macro macro)) | |
32 | ||
33 | | (macro?) | |
34 | ? abort (illegal-arguments ()) | |
35 | ||
36 | '<<SPEC' | |
37 | ||
38 | (require macro?) |
0 | ;'<<SPEC' | |
1 | ||
2 | ### `operator?` ### | |
3 | ||
4 | -> Tests for functionality "Evaluate core Robin Expression" | |
5 | ||
6 | `operator?` evaluates its argument, then evaluates to `#t` if it is an operator, | |
7 | or `#f` if it is not. | |
8 | ||
9 | | (operator? (macro (args env) args)) | |
10 | = #t | |
11 | ||
12 | Intrinsic operators are operators. | |
13 | ||
14 | | (operator? macro) | |
15 | = #t | |
16 | ||
17 | Literal symbols are not operators, even if they're the name of one. | |
18 | ||
19 | | (operator? ((macro (args env) (head args)) macro)) | |
20 | = #f | |
21 | ||
22 | Numbers are not operators. | |
23 | ||
24 | | (operator? 5) | |
25 | = #f | |
26 | ||
27 | The argument to `operator?` may (naturally) be any type, but there must be | |
28 | exactly one argument. | |
29 | ||
30 | | (operator? macro macro) | |
31 | ? abort (illegal-arguments (macro macro)) | |
32 | ||
33 | | (operator?) | |
34 | ? abort (illegal-arguments ()) | |
35 | ||
36 | '<<SPEC' | |
37 | ||
38 | (require operator?) |