/
_poormac.crk
113 lines (92 loc) · 2.93 KB
/
_poormac.crk
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
// Copyright 2010-2011 Google Inc.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
# Poor man's macros - for use in lang.crk
# Note that everything here is run in bootstrapping mode - Object, String and
# the like do not exist.
#
# These kinds of macros are used as follows:
# @poormac m 3 if ($1 == $2) $3('something is wrong'); $$
# @m 10 20 puts
import crack.runtime free;
import crack.compiler Token, CrackContext;
# if you get an error here about "Incrrect type for initializer." then you are
# trying to use this after bootstrapping. Silly programmer. Use
# crack.ann instead.
byteptr test = 'test string';
class TokNode {
Token tok;
uint arg;
TokNode next;
oper init(Token tok, TokNode next) : tok = tok, next = next {}
oper init(uint arg, TokNode next) : arg = arg, next = next {}
}
class Macro {
TokNode first;
uint numArgs;
void put(uint arg) { first = TokNode(arg, first); }
void put(Token tok) { first = TokNode(tok, first); }
}
void expand(CrackContext ctx) {
m := Macro.unsafeCast(ctx.getUserData());
args := array[Token](m.numArgs);
# read the args
for (uint i = 0; i < m.numArgs; ++i) {
Token tok = ctx.getToken();
args[i] = tok;
args[i].oper bind();
}
# push the tokens back into the stream with argument replacement
for (TokNode elem = m.first; elem !is null; elem = elem.next)
if (elem.tok !is null)
ctx.putBack(elem.tok);
else
ctx.putBack(args[elem.arg]);
# release the args
for (uint i = 0; i < m.numArgs; ++i)
args[i].oper release();
}
uint atoi(byteptr val) {
uint result = 0;
for (uint i; val[i]; ++i)
result = result * 10 + val[i] - 48;
return result;
}
void define(CrackContext ctx) {
Macro m = {};
# get the macro name
Token nameTok = ctx.getToken();
# get the number of arguments
Token tok = ctx.getToken();
m.numArgs = atoi(tok.getText());
# parse the body of the macro
tok = ctx.getToken();
bool gotDollar = 0;
while (!tok.isEnd()) {
if (gotDollar) {
if (tok.isInteger()) {
arg := atoi(tok.getText()) - 1;
if (arg < 0 || arg > m.numArgs) {
printint(arg);
ctx.error(tok, 'argument index out of bounds');
}
m.put(arg);
} else if (tok.isDollar()) {
break;
} else {
ctx.error(tok, 'illegal token following dollar-sign');
}
gotDollar = 0;
} else {
if (tok.isDollar())
gotDollar = 1;
else
m.put(tok);
}
tok = ctx.getToken();
}
ctx.storeAnnotation(nameTok.getText(), expand, m);
}