blob: bcb8d4e9d0d2bf2ebe0fdcef6f2547c7e8650026 [file] [log] [blame]
Jack Jansendbc692e2001-03-10 13:24:41 +00001#include <AEDataModel.h>
2
3#define DEBUG 0
4
5#define kComponentSignatureString "BBPy.LM"
6#include <Debugging.h>
7
8
9#include <BBLMInterface.h>
10#include <BBXTInterface.h>
11//#include <BBLMTextIterator.h>
12
13#include <ctype.h>
14#include <string.h>
15#include <stdio.h>
16#include <stdarg.h>
17
18#include <Sound.h>
19
20#if DEBUG
21void debugf_(const char* func,const char* fileName,long line, const char*fmt,...)
22{
23 va_list arg;
24 char msg[256];
25 va_start(arg, fmt);
26 vsnprintf(msg,256 ,fmt, arg);
27 DebugAssert(COMPONENT_SIGNATURE, DEBUG_NO_OPTIONS, kComponentSignatureString ": " , msg, nil, fileName, line, 0 );
28
29 //debug_string(msg);
30}
31#define debugf(FMT,...) debugf_( __FUNCTION__,__FILE__, __LINE__,FMT,__VA_ARGS__);
32#else
33#define debugf(FMT,...)
34#endif
35
36typedef const char *Str;
37
38
39enum{
40 kPyBBLMStringSubst = kBBLMFirstUserRunKind
41};
42
43#define iswordchar(x) (isalnum(x)||x=='_')
44
45
46struct runloc{
47 bool past_gap;
48 long pos;
49 long last_start;
50 unsigned char*p;
51};
52
53char start(struct runloc& r,BBLMParamBlock &pb)
54{
55 r.past_gap = false;
56 r.last_start = pb.fCalcRunParams.fStartOffset;
57 r.pos = pb.fCalcRunParams.fStartOffset;
58 r.p = ((unsigned char*)pb.fText) + pb.fCalcRunParams.fStartOffset;
Jack Jansen6f84ed52001-05-17 12:45:13 +000059 // Adjust for the gap if weÕre not already past it.
Jack Jansendbc692e2001-03-10 13:24:41 +000060 if ((!r.past_gap) && (r.pos >= pb.fTextGapLocation)){
61 r.p += pb.fTextGapLength;
62 r.past_gap = true;
63 }
64 return *r.p;
65
66}
67
68char nextchar(struct runloc&r,BBLMParamBlock &pb)
69{
70 if ( r.pos< pb.fTextLength){
71 ++r.pos;
72 ++r.p;
73 if ((!r.past_gap) && (r.pos >= pb.fTextGapLocation)){
74 r.p += pb.fTextGapLength;
75 r.past_gap = true;
76 }
77 return *r.p;
78 }
79 else{
80 return 0;
81 }
82}
83
84bool addRun(BBLMRunCode kind, int start,int len , const BBLMCallbackBlock& bblm_callbacks)
85{
86 if (len > 0){ // Tie off the code run we were in, unless the length is zero.
87 debugf("Run %d %d:%d", kind, start, start+len-1 );
88 return bblmAddRun( &bblm_callbacks, 'Pyth',
89 kind, start, len, false);
90
91 }
92 else{
93 return true;
94 }
95}
96
97bool addRunBefore (BBLMRunCode kind,struct runloc& r, const BBLMCallbackBlock& bblm_callbacks)
98{
99 bool more_runs = addRun(kind, r.last_start, r.pos - r.last_start, bblm_callbacks);
100 r.last_start = r.pos;
101 return more_runs;
102}
103
104bool addRunTo (BBLMRunCode kind, struct runloc& r, const BBLMCallbackBlock& bblm_callbacks)
105{
106 bool more_runs = addRun(kind, r.last_start, r.pos - r.last_start+1, bblm_callbacks);
107 r.last_start = r.pos+1;
108 return more_runs;
109}
110
111
112bool colorstr( char delim,
113 BBLMParamBlock &pb,
114 struct runloc &r,
115 const BBLMCallbackBlock &bblm_callbacks)
116{
117 bool tripple = false , pers = false, lookup = false, more_runs = true;
118 char c = nextchar(r,pb);
119
120 if (c == delim){
121 c = nextchar(r,pb);
122 if (c == delim){
123 tripple = true;
124 c = nextchar(r,pb);
125 }
126 else{
127 //double
128 return addRunBefore(kBBLMRunIsSingleString,r,bblm_callbacks);
129 }
130 }
131 while (c && more_runs){
132 if (pers ){
133 if (isalpha(c)){
134 more_runs = addRunTo(kPyBBLMStringSubst,r,bblm_callbacks);
135 }
136 else if (c == '('){
137 lookup = true;
138 }
139 }
140 pers = false;
141 if (c == delim){
142 if (tripple){
143 if ((c = nextchar(r,pb))== delim && (c = nextchar(r,pb)) == delim){
144 break; // end of tripple-quote.
145 }
146 }
147 else{
148 break; // end of single-quote.
149 }
150
151 }
152 else if (c== '\\'){
153 nextchar(r,pb);
154 }
155 else if (c=='\r'||c=='\n'){
156 if (!tripple){
157 break;
158 }
159 }
160 else if (c=='%'){
161 more_runs = addRunBefore(kBBLMRunIsSingleString,r,bblm_callbacks);
162 pers = true;
163 }
164 else if (c==')' && lookup){
165 more_runs = addRunTo(kPyBBLMStringSubst,r,bblm_callbacks);
166 lookup = false;
167 }
168 c = nextchar(r,pb);
169 }
170 return more_runs && addRunTo(lookup?kPyBBLMStringSubst:kBBLMRunIsSingleString,r,bblm_callbacks);
171}
172
173bool colorcomment(BBLMParamBlock &pb,
174 struct runloc &r,
175 const BBLMCallbackBlock &bblm_callbacks)
176{
177 while (char c = nextchar(r,pb)){
178 if (c=='\r'|| c=='\n'){
179 break;
180 }
181 }
182 return addRunTo(kBBLMRunIsLineComment,r,bblm_callbacks);
183}
184
185void CalculateRuns(BBLMParamBlock &pb,
186 const BBLMCallbackBlock &bblm_callbacks)
187
188{
189 const struct rundesc *state = NULL;
190 bool more_runs=true;
191
192 struct runloc r;
193
194 char c = start(r,pb);
195
196 while (c && more_runs){
197 loop:
198 // Process a char
199 if (state==NULL){
200 //If we're in the basic 'code' state, check for each interesting char (rundelims[i].start).
201 switch (c){
202 case '\'':
203 case '"':
204 more_runs = addRunBefore(kBBLMRunIsCode,r,bblm_callbacks);
205 if (more_runs){
206 more_runs = colorstr(c,pb,r,bblm_callbacks);
207 }
208 break;
209 case '#' :
210 more_runs = addRunBefore(kBBLMRunIsCode,r,bblm_callbacks);
211 if (more_runs){
212 more_runs = colorcomment(pb,r,bblm_callbacks);
213 }
214 break;
215 default:
216 break;
217 }
218
219 }
220 c = nextchar(r,pb);
221 }
222 if (more_runs){
223 addRunBefore(kBBLMRunIsCode,r,bblm_callbacks);
224 }
225
226
227}
228static void AdjustRange(BBLMParamBlock &params,
229 const BBLMCallbackBlock &callbacks)
230{
231 DescType language;
232 BBLMRunCode kind;
233 SInt32 charPos;
234 SInt32 length;
235 UInt32 index = params.fAdjustRangeParams.fStartIndex;
236
237 while( index > 0 &&
238 bblmGetRun(&callbacks, index, language, kind, charPos, length) &&
239 (kind==kPyBBLMStringSubst||kind==kBBLMRunIsSingleString)){
240 index--;
241 };
242 params.fAdjustRangeParams.fStartIndex = index;
243}
244
245
246// The next couple funcs process the text of a file assumming it's in 1 piece in memory,
247// so they may not be called from CalculateRuns.
248
249bool matchword(BBLMParamBlock &pb, const char *pat ,unsigned long *pos)
250{
251 const char *asciText = (const char *) (pb.fTextIsUnicode?NULL:pb.fText);
252
253 int i;
254 for (i=0; pat[i]; i++){
255 if (*pos+i>=pb.fTextLength){
256 return false;
257 }
258 if (asciText[*pos+i] != pat[i]){
259 return false;
260 }
261 }
262 if ((*pos+i<pb.fTextLength)&&iswordchar(asciText[*pos+i])){
263 return false;
264 }
265 *pos+=i;
266 return true;
267}
268
269int matchindent(BBLMParamBlock &pb, UInt32 *pos)
270{
271 const char *asciText = (const char *) (pb.fTextIsUnicode?NULL:pb.fText);
272 int indent=0;
273
274 while(*pos<pb.fTextLength){
275 switch (/*(char)(pb.fTextIsUnicode?uniText[pos]:*/asciText[*pos]/*)*/){
276 case ' ':
277 ++*pos;
278 indent++;
279 break;
280 case '\t':
281 ++*pos;
282 indent+=8;
283 break;
284 case '#':
285 return -1;
286 break;
287 default:
288 return indent;
289 break;
290 }
291 }
292}
293
294
295void eat_line(BBLMParamBlock &pb, unsigned long* pos)
296{
297 const char *asciText = (const char *) (pb.fTextIsUnicode?NULL:pb.fText);
298 while (asciText[*pos]!='\r' && asciText[*pos]!='\n' && *pos<pb.fTextLength) {++*pos;}
299 while ((asciText[*pos]=='\r' || asciText[*pos]=='\n') && *pos<pb.fTextLength) {++*pos;}
300
301}
302
303void addItem(BBLMParamBlock &pb, UInt32 pos, int nest, BBLMFunctionKinds kind,
304 const BBLMCallbackBlock *bblm_callbacks)
305{
306 UInt32 funcstartpos = pos;
307 UInt32 funcnamelen=0;
308 UInt32 offset=0;
309 const char *asciText = (const char *) pb.fText;
310 UInt32 index;
311 OSErr err;
312
313 while (isspace(asciText[pos]) && pos<pb.fTextLength) {++pos;}
314 UInt32 fnamestart = pos;
315 while ((isalnum(asciText[pos])||asciText[pos]=='_') && pos<pb.fTextLength) {pos++; funcnamelen++;}
316
317 err = bblmAddTokenToBuffer( bblm_callbacks,
318 pb.fFcnParams.fTokenBuffer,
319 (void*)&asciText[fnamestart],
320 funcnamelen,
321 pb.fTextIsUnicode,
322 &offset);
323 BBLMProcInfo procInfo;
324 procInfo.fFunctionStart = fnamestart; // char offset in file of first character of function
325 procInfo.fFunctionEnd = pos; // char offset of last character of function
326
327 procInfo.fSelStart = fnamestart; // first character to select when choosing function
328 procInfo.fSelEnd = pos; // last character to select when choosing function
329
330 procInfo.fFirstChar = fnamestart; // first character to make visible when choosing function
331
332 procInfo.fKind = kind;
333
334 procInfo.fIndentLevel = nest; // indentation level of token
335 procInfo.fFlags = 0; // token flags (see BBLMFunctionFlags)
336 procInfo.fNameStart = offset; // char offset in token buffer of token name
337 procInfo.fNameLength = funcnamelen; // length of token name
338
339 err = bblmAddFunctionToList(bblm_callbacks,
340 pb.fFcnParams.fFcnList,
341 procInfo,
342 &index);
343}
344
345
346
347enum{
348 maxnest=5
349};
350
351void ScanForFunctions(BBLMParamBlock &pb,
352 const BBLMCallbackBlock &bblm_callbacks)
353{
354
355 const char *asciText = (const char *) (pb.fTextIsUnicode?NULL:pb.fText);
356 UniCharPtr uniText = (UniCharPtr) (pb.fTextIsUnicode?pb.fText:NULL);
357
358 int indents[maxnest]= {0};
359 int nest = 0;
360
361 UInt32 pos=0; // current character offset
362
363
364 while (pos<pb.fTextLength){
365
366 int indent = matchindent(pb, &pos);
367
368 if (indent >= 0){
369 for (int i=0; i <= nest; i++){
370 if (indent<=indents[i]){
371 nest = i;
372 indents[nest]=indent;
373 goto x;
374 }
375 }
376 indents[++nest]=indent;
377 x:
378
379 if (matchword(pb,"def",&pos)){
380 addItem( pb, pos, nest, kBBLMFunctionMark, &bblm_callbacks);
381 }
382 else if (matchword(pb, "class", &pos)){
383 addItem( pb, pos, nest, kBBLMTypedef, &bblm_callbacks);
384 }
385 }
386 eat_line(pb,&pos);
387 }
388
389}
390
391OSErr main( BBLMParamBlock &params,
392 const BBLMCallbackBlock &bblm_callbacks,
393 const BBXTCallbackBlock &bbxt_callbacks)
394{
395 OSErr result;
396
397 if ((params.fSignature != kBBLMParamBlockSignature) ||
398 (params.fLength < sizeof(BBLMParamBlock)))
399 {
400 return paramErr;
401 }
402
403 switch (params.fMessage)
404 {
405 case kBBLMInitMessage:
406 case kBBLMDisposeMessage:
407 {
408 result = noErr; // nothing to do
409 break;
410 }
411
412 case kBBLMCalculateRunsMessage:
413 CalculateRuns(params, bblm_callbacks);
414 result = noErr;
415 break;
416
417 case kBBLMScanForFunctionsMessage:
418 ScanForFunctions(params, bblm_callbacks);
419 result = noErr;
420 break;
421
422 case kBBLMAdjustRangeMessage:
423 AdjustRange(params, bblm_callbacks);
424 result = noErr;
425 break;
426
427 case kBBLMMapRunKindToColorCodeMessage:
428 switch (params.fMapRunParams.fRunKind){
429 case kPyBBLMStringSubst:
430 params.fMapRunParams.fColorCode = kBBLMSGMLAttributeNameColor;
431 params.fMapRunParams.fMapped = true;
432 break;
433 default:
434 params.fMapRunParams.fMapped = false;
435 }
436 result = noErr;
437 break;
438
439 case kBBLMEscapeStringMessage:
440 case kBBLMAdjustEndMessage:
441 case kBBLMMapColorCodeToColorMessage:
442 case kBBLMSetCategoriesMessage:
443 case kBBLMMatchKeywordMessage:
444 {
445 result = userCanceledErr;
446 break;
447 }
448
449 default:
450 {
451 result = paramErr;
452 break;
453 }
454 }
455 return result;
456}