source: dev/trunk/abdev/BasicCompiler_Common/Compile.cpp@ 253

Last change on this file since 253 was 253, checked in by dai_9181, 17 years ago
File size: 17.1 KB
Line 
1#include "stdafx.h"
2
3#include <jenga/include/smoothie/Smoothie.h>
4#include <jenga/include/smoothie/LexicalAnalysis.h>
5#include <jenga/include/smoothie/SmoothieException.h>
6
7#include <LexicalScope.h>
8#include <CodeGenerator.h>
9#include <Compiler.h>
10#include <NamespaceSupporter.h>
11
12#include "../BasicCompiler_Common/common.h"
13
14#ifdef _AMD64_
15#include "../BasicCompiler64/opcode.h"
16#else
17#include "../BasicCompiler32/opcode.h"
18#endif
19
20#include <Exception.h>
21
22//ラベルアドレス
23LABEL *pLabelNames;
24int MaxLabelNum;
25
26//グローバル変数初期バッファ
27BYTE *initGlobalBuf;
28
29//With情報
30WITHINFO WithInfo;
31
32
33
34///////////////////////////////////////////////////
35// トークンを取得
36///////////////////////////////////////////////////
37void GetIdentifierToken( char *token, const char *source, int &pos ){
38 for( int i=0; ; i++, pos++ ){
39 if( ! IsVariableChar( source[pos] ) ){
40 token[i] = 0;
41 break;
42 }
43 token[i] = source[pos];
44 }
45}
46
47
48///////////////////////////////////////////////////
49// 対になっているステートメントを飛び越す
50// ※グローバル領域用
51///////////////////////////////////////////////////
52int JumpStatement(const char *source, int &pos){
53 if( source[pos] != 1 ) return 0;
54
55 if( ! IsCommandDelimitation( source[pos - 1] ) ){
56 //直前がコマンド区切りではない場合
57 return 0;
58 }
59
60 char cStatement = source[pos + 1];
61
62 char cEnd = GetEndXXXCommand( cStatement );
63 if( cEnd == 0 ) return 0;
64
65 pos += 2;
66 while( ! ( source[pos] == 1 && source[pos + 1] == cEnd ) ){
67
68 if( source[pos] == '\0' ){
69 char temporary[64];
70 GetDefaultNameFromES( cStatement, temporary );
71 SetError( 22, temporary, pos );
72 return -1;
73 }
74
75 pos++;
76 }
77 if( ! ( source[pos] == '\0' || source[pos + 2] == '\0' ) ){
78 pos += 2;
79 }
80
81 return 1;
82}
83
84
85void NextLine(void){
86 extern HANDLE hHeap;
87 extern int MaxLineInfoNum;
88 extern LINEINFO *pLineInfo;
89 if(MaxLineInfoNum){
90 extern int obp;
91 if(pLineInfo[MaxLineInfoNum-1].TopObp==obp){
92 pLineInfo[MaxLineInfoNum-1].TopCp=cp;
93 return;
94 }
95 }
96 pLineInfo=(LINEINFO *)HeapReAlloc(hHeap,0,pLineInfo,(MaxLineInfoNum+1)*sizeof(LINEINFO));
97 pLineInfo[MaxLineInfoNum].TopCp=cp;
98 extern int obp;
99 pLineInfo[MaxLineInfoNum].TopObp=obp;
100
101 extern BOOL bDebugSupportProc;
102 extern BOOL bSystemProc;
103 pLineInfo[MaxLineInfoNum].dwCodeType=0;
104 if(bDebugSupportProc)
105 pLineInfo[MaxLineInfoNum].dwCodeType|=CODETYPE_DEBUGPROC;
106 if(bSystemProc)
107 pLineInfo[MaxLineInfoNum].dwCodeType|=CODETYPE_SYSTEMPROC;
108
109 MaxLineInfoNum++;
110}
111
112void ChangeOpcode(char *Command){
113 extern HANDLE hHeap;
114
115 if(Command[0]=='\0')
116 {
117 return;
118 }
119
120 trace_for_sourcecodestep( FormatEscapeSequenceStringToDefaultString(Command) );
121
122 if(Command[0]=='*'&&IsVariableTopChar(Command[1])){
123 //Goto先ラベル
124 pLabelNames=(LABEL *)HeapReAlloc(hHeap,0,pLabelNames,(MaxLabelNum+1)*sizeof(LABEL));
125 pLabelNames[MaxLabelNum].pName=(char *)HeapAlloc(hHeap,0,lstrlen(Command+1)+1);
126 lstrcpy(pLabelNames[MaxLabelNum].pName,Command+1);
127 extern int obp;
128 pLabelNames[MaxLabelNum].address=obp;
129 MaxLabelNum++;
130
131 //書き込みスケジュール
132 GotoLabelSchedules::iterator it = compiler.codeGenerator.gotoLabelSchedules.begin();
133 while( it != compiler.codeGenerator.gotoLabelSchedules.end() )
134 {
135 if( (*it)->GetName() == Command+1 )
136 {
137 compiler.codeGenerator.opfix_JmpPertialSchedule( (*it) );
138
139 //詰める
140 it = compiler.codeGenerator.gotoLabelSchedules.erase( it );
141 }
142 else
143 {
144 it++;
145 }
146 }
147 return;
148 }
149 if(Command[0]==1){
150 switch(Command[1]){
151 case ESC_CONST:
152 OpcodeDim(Command+2, DIMFLAG_CONST);
153 break;
154
155 case ESC_TYPEDEF:
156 if( UserProc::IsLocalAreaCompiling() ){
157 // ローカル領域をコンパイルしているとき
158 SetError(65,"TypeDef",cp );
159 }
160
161 //既に収集済み
162 break;
163
164 case ESC_STATIC:
165 OpcodeDim(Command+2,DIMFLAG_STATIC);
166 break;
167
168 case ESC_IF:
169 OpcodeIf(Command+2);
170 break;
171 case ESC_EXITWHILE:
172 {
173 LexicalScope *pScope = compiler.codeGenerator.lexicalScopes.SearchScope( LexicalScope::SCOPE_TYPE_WHILE );
174 if( !pScope ){
175 SetError(12,"Exit While",cp);
176 return;
177 }
178 pScope->Break();
179 }
180 break;
181 case ESC_EXITFOR:
182 {
183 LexicalScope *pScope = compiler.codeGenerator.lexicalScopes.SearchScope( LexicalScope::SCOPE_TYPE_FOR );
184 if( !pScope ){
185 SetError(12,"Exit For",cp);
186 return;
187 }
188 pScope->Break();
189 }
190 break;
191 case ESC_EXITDO:
192 {
193 LexicalScope *pScope = compiler.codeGenerator.lexicalScopes.SearchScope( LexicalScope::SCOPE_TYPE_DO );
194 if( !pScope ){
195 SetError(12,"Exit Do",cp);
196 return;
197 }
198 pScope->Break();
199 }
200 break;
201 case ESC_CONTINUE:
202 OpcodeContinue();
203 break;
204
205 case ESC_EXITSUB:
206 case ESC_EXITFUNCTION:
207 case ESC_EXITMACRO:
208 OpcodeExitSub();
209 break;
210
211 case ESC_SELECTCASE:
212 OpcodeSelect(Command+2);
213 break;
214 case ESC_CASE:
215 case ESC_CASEELSE:
216 OpcodeCase(Command+2);
217 break;
218
219 case ESC_WITH:
220 extern WITHINFO WithInfo;
221
222 WithInfo.ppName=(char **)HeapReAlloc(hHeap,0,WithInfo.ppName,(WithInfo.num+1)*sizeof(char **));
223 WithInfo.ppName[WithInfo.num]=(char *)HeapAlloc(hHeap,0,lstrlen(Command+2)+1);
224 lstrcpy(WithInfo.ppName[WithInfo.num],Command+2);
225
226 WithInfo.pWithCp=(int *)HeapReAlloc(hHeap,0,WithInfo.pWithCp,(WithInfo.num+1)*sizeof(int));
227 WithInfo.pWithCp[WithInfo.num]=cp;
228
229 WithInfo.num++;
230 break;
231 case ESC_ENDWITH:
232 if(WithInfo.num<=0){
233 SetError(12,"End With",cp);
234 return;
235 }
236 WithInfo.num--;
237 HeapDefaultFree(WithInfo.ppName[WithInfo.num]);
238 break;
239 case ESC_DECLARE:
240 if( UserProc::IsLocalAreaCompiling() ){
241 // ローカル領域をコンパイルしているとき
242 SetError(65,"Declare",cp );
243 }
244 break;
245
246 case ESC_NAMESPACE:
247 compiler.GetNamespaceSupporter().GetLivingNamespaceScopes().push_back( Command + 2 );
248 break;
249 case ESC_ENDNAMESPACE:
250 if( compiler.GetNamespaceSupporter().GetLivingNamespaceScopes().size() <= 0 ){
251 SetError(12,"End Namespace",cp);
252 }
253 compiler.GetNamespaceSupporter().GetLivingNamespaceScopes().pop_back();
254 break;
255 case ESC_IMPORTS:
256 compiler.GetNamespaceSupporter().ImportsNamespace( Command + 2 );
257 break;
258 case ESC_CLEARNAMESPACEIMPORTED:
259 compiler.GetNamespaceSupporter().GetImportedNamespaces().clear();
260 break;
261
262 //Tryによる例外処理
263 case ESC_TRY:
264 Exception::TryCommand();
265 break;
266 case ESC_CATCH:
267 Exception::CatchCommand();
268 break;
269 case ESC_FINALLY:
270 Exception::FinallyCommand();
271 break;
272 case ESC_ENDTRY:
273 Exception::EndTryCommand();
274 break;
275 case ESC_THROW:
276 Exception::ThrowCommand( Command + 2 );
277 break;
278
279 default:
280 char temporary[64];
281 GetDefaultNameFromES(Command[1],temporary);
282 SetError(30,temporary,cp);
283 break;
284 }
285 return;
286 }
287 switch(MAKEWORD(Command[1],Command[0])){
288 case COM_DIM:
289 OpcodeDim(Command+2,0);
290 break;
291 case COM_DELETE:
292 OpcodeDelete(Command+2, false);
293 break;
294 case COM_SWEEPINGDELETE:
295 OpcodeDelete(Command+2, true);
296 break;
297
298 case COM_GOTO:
299 OpcodeGoto(Command+2);
300 break;
301 case COM_WHILE:
302 OpcodeWhile(Command+2);
303 break;
304 case COM_FOR:
305 OpcodeFor(Command+2);
306 break;
307 case COM_DO:
308 OpcodeDo(Command+2);
309 break;
310
311 case COM_GOSUB:
312 OpcodeGosub(Command+2);
313 break;
314 case COM_RETURN:
315 OpcodeReturn(Command+2);
316 break;
317
318 case COM_SETDOUBLE:
319 OpcodeSetPtrData(Command+2,DEF_DOUBLE);
320 break;
321 case COM_SETSINGLE:
322 OpcodeSetPtrData(Command+2,DEF_SINGLE);
323 break;
324 case COM_SETQWORD:
325 OpcodeSetPtrData(Command+2,DEF_QWORD);
326 break;
327 case COM_SETDWORD:
328 OpcodeSetPtrData(Command+2,DEF_DWORD);
329 break;
330 case COM_SETWORD:
331 OpcodeSetPtrData(Command+2,DEF_WORD);
332 break;
333 case COM_SETBYTE:
334 OpcodeSetPtrData(Command+2,DEF_BYTE);
335 break;
336
337 case COM_DEBUG:
338 extern BOOL bDebugCompile;
339 //int 3
340 if(bDebugCompile)
341 {
342 breakpoint;
343 }
344#if defined(_DEBUG)
345 else
346 {
347 breakpoint;
348 }
349#endif
350 break;
351
352 case COM_LET:
353 OpcodeCalc(Command+2);
354 break;
355 default:
356 OpcodeOthers(Command);
357 break;
358 }
359}
360
361void GetGlobalDataForDll(void){
362 extern char *basbuf;
363 extern HANDLE hHeap;
364 int i2,BufferSize;
365 char *Command;
366 DWORD dwRetCode;
367
368 dwRetCode=0;
369 BufferSize=128;
370 Command=(char *)HeapAlloc(hHeap,0,BufferSize);
371 for(cp++,i2=0;;cp++,i2++){
372 if(i2>=BufferSize){
373 //バッファ領域が足りなくなった場合はバッファを増量する
374 BufferSize+=128;
375 Command=(char *)HeapReAlloc(hHeap,0,Command,BufferSize);
376 }
377 if(basbuf[cp]=='\"'){
378 Command[i2]=basbuf[cp];
379 for(cp++,i2++;;cp++,i2++){
380 if(i2>=BufferSize){
381 //バッファ領域が足りなくなった場合はバッファを増量する
382 BufferSize+=128;
383 Command=(char *)HeapReAlloc(hHeap,0,Command,BufferSize);
384 }
385 Command[i2]=basbuf[cp];
386 if(basbuf[cp]=='\"') break;
387 }
388 continue;
389 }
390 if(IsCommandDelimitation(basbuf[cp])){
391 Command[i2]=0;
392
393 if(Command[0]==1&&Command[1]==ESC_SUB){
394 i2=cp;
395 while(!(basbuf[cp]==1&&basbuf[cp+1]==ESC_ENDSUB)){
396 if(basbuf[cp]=='\0'){
397 SetError(22,"Sub",i2);
398 break;
399 }
400 cp++;
401 }
402 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
403 cp+=2;
404 i2=-1;
405 continue;
406 }
407 if(Command[0]==1&&Command[1]==ESC_FUNCTION){
408 i2=cp;
409 while(!(basbuf[cp]==1&&basbuf[cp+1]==ESC_ENDFUNCTION)){
410 if(basbuf[cp]=='\0'){
411 SetError(22,"Function",i2);
412 break;
413 }
414 cp++;
415 }
416 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
417 cp+=2;
418 i2=-1;
419 continue;
420 }
421 if(Command[0]==1&&Command[1]==ESC_MACRO){
422 i2=cp;
423 while(!(basbuf[cp]==1&&basbuf[cp+1]==ESC_ENDMACRO)){
424 if(basbuf[cp]=='\0'){
425 SetError(22,"Macro",i2);
426 break;
427 }
428 cp++;
429 }
430 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
431 cp+=2;
432 i2=-1;
433 continue;
434 }
435 if(Command[0]==1&&Command[1]==ESC_TYPE){
436 i2=cp;
437 while(!(basbuf[cp]==1&&basbuf[cp+1]==ESC_ENDTYPE)){
438 if(basbuf[cp]=='\0'){
439 SetError(22,"Type",i2);
440 break;
441 }
442 cp++;
443 }
444 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
445 cp+=2;
446 i2=-1;
447 continue;
448 }
449 if(Command[0]==1&&Command[1]==ESC_CLASS){
450 i2=cp;
451 while(!(basbuf[cp]==1&&basbuf[cp+1]==ESC_ENDCLASS)){
452 if(basbuf[cp]=='\0'){
453 SetError(22,"Class",i2);
454 break;
455 }
456 cp++;
457 }
458 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
459 cp+=2;
460 i2=-1;
461 continue;
462 }
463 if(Command[0]==1&&Command[1]==ESC_INTERFACE){
464 i2=cp;
465 while(!(basbuf[cp]==1&&basbuf[cp+1]==ESC_ENDINTERFACE)){
466 if(basbuf[cp]=='\0'){
467 SetError(22,"Interface",i2);
468 break;
469 }
470 cp++;
471 }
472 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
473 cp+=2;
474 i2=-1;
475 continue;
476 }
477
478 //DLLのグローバルデータに必要なコマンドだけ
479 if(MAKEWORD(Command[1],Command[0])==COM_DIM)
480 OpcodeDim(Command+2,0);
481
482 // ネイティブコードバッファの再確保
483 ReallocNativeCodeBuffer();
484
485 if(basbuf[cp]=='\0') break;
486 i2=-1;
487 continue;
488 }
489 Command[i2]=basbuf[cp];
490 }
491 HeapDefaultFree(Command);
492}
493DWORD CompileBuffer(char Return_Sequence,WORD Return_Command){
494 extern char *basbuf;
495 extern HANDLE hHeap;
496 int i,i2,i3,i4,BufferSize,ScopeStart;
497 char *Command,temporary[VN_SIZE],*temp2,temp3[32];
498 DWORD dwRetCode;
499
500 ScopeStart=cp;
501
502 dwRetCode=0;
503 BufferSize=128;
504 Command=(char *)HeapAlloc(hHeap,0,BufferSize);
505
506 for(cp++,i2=0;;cp++,i2++){
507 if(i2>=BufferSize){
508 //バッファ領域が足りなくなった場合はバッファを増量する
509 BufferSize+=128;
510 Command=(char *)HeapReAlloc(hHeap,0,Command,BufferSize);
511 }
512 if(basbuf[cp]=='\"'){
513 Command[i2]=basbuf[cp];
514 for(cp++,i2++;;cp++,i2++){
515 if(i2>=BufferSize){
516 //バッファ領域が足りなくなった場合はバッファを増量する
517 BufferSize+=128;
518 Command=(char *)HeapReAlloc(hHeap,0,Command,BufferSize);
519 }
520 Command[i2]=basbuf[cp];
521 if(basbuf[cp]=='\"') break;
522 }
523 continue;
524 }
525 if(IsCommandDelimitation(basbuf[cp])){
526 Command[i2]=0;
527
528 if(Command[0]==1&&Command[1]==ESC_LINENUM){
529 for(i=2,i2=0;;i++,i2++){
530 if(Command[i]==','){
531 temporary[i2]=0;
532 break;
533 }
534 temporary[i2]=Command[i];
535 }
536 i3=atoi(temporary);
537 i4=i+1;
538
539 //Goto先ラベル
540 pLabelNames=(LABEL *)HeapReAlloc(hHeap,0,pLabelNames,(MaxLabelNum+1)*sizeof(LABEL));
541 pLabelNames[MaxLabelNum].pName=0;
542 pLabelNames[MaxLabelNum].line=i3;
543 extern int obp;
544 pLabelNames[MaxLabelNum].address=obp;
545 MaxLabelNum++;
546
547 //書き込みスケジュール
548 GotoLabelSchedules::iterator it = compiler.codeGenerator.gotoLabelSchedules.begin();
549 while( it != compiler.codeGenerator.gotoLabelSchedules.end() )
550 {
551 if( (*it)->GetName().size() == 0 && (*it)->GetLineNum() == i3 )
552 {
553 compiler.codeGenerator.opfix_JmpPertialSchedule( (*it) );
554
555 //詰める
556 it = compiler.codeGenerator.gotoLabelSchedules.erase( it );
557 }
558 else
559 {
560 it++;
561 }
562 }
563
564 temp2=(char *)HeapAlloc(hHeap,0,lstrlen(Command+i4)+1);
565 lstrcpy(temp2,Command+i4);
566 lstrcpy(Command,temp2);
567 HeapDefaultFree(temp2);
568 }
569
570 if(Command[0]==1&&
571 (((Command[1]==ESC_VIRTUAL||Command[1]==ESC_OVERRIDE)&&Command[2]==1&&(Command[3]==ESC_SUB||Command[3]==ESC_FUNCTION))||
572 Command[1]==ESC_SUB||
573 Command[1]==ESC_FUNCTION||
574 Command[1]==ESC_MACRO||
575 Command[1]==ESC_TYPE||
576 Command[1]==ESC_CLASS||
577 Command[1]==ESC_INTERFACE||
578 Command[1]==ESC_ENUM||
579 (Command[1]==ESC_CONST&&Command[2]==1&&Command[3]==ESC_ENUM)
580 )
581 ){
582 if(Command[1]==ESC_VIRTUAL||Command[1]==ESC_OVERRIDE||Command[1]==ESC_CONST){
583 GetDefaultNameFromES(Command[3],temporary);
584 }
585 else{
586 GetDefaultNameFromES(Command[1],temporary);
587 }
588 if(Return_Sequence){
589 SetError(12,temporary,cp);
590 break;
591 }
592
593 if(Command[1]==ESC_CONST) i3=GetEndXXXCommand(Command[3]);
594 else i3=GetEndXXXCommand(Command[1]);
595 for(i2=cp;;cp++){
596 if(basbuf[cp]==1){
597 if(basbuf[cp+1]==i3) break;
598 if(Command[1]==ESC_CLASS||Command[1]==ESC_INTERFACE){
599 //クラス、インターフェイスではSub、Functionの定義を可能にしておく
600 if(basbuf[cp+1]==ESC_MACRO||
601 basbuf[cp+1]==ESC_TYPE||
602 basbuf[cp+1]==ESC_CLASS||
603 basbuf[cp+1]==ESC_INTERFACE||
604 basbuf[cp+1]==ESC_ENUM){
605 GetDefaultNameFromES(basbuf[cp+1],temp3);
606 SetError(12,temp3,cp);
607 }
608 }
609 else{
610 if(basbuf[cp-1]!='*'&&(
611 basbuf[cp+1]==ESC_VIRTUAL||
612 basbuf[cp+1]==ESC_OVERRIDE||
613 basbuf[cp+1]==ESC_SUB||
614 basbuf[cp+1]==ESC_FUNCTION||
615 basbuf[cp+1]==ESC_MACRO||
616 basbuf[cp+1]==ESC_TYPE||
617 basbuf[cp+1]==ESC_CLASS||
618 basbuf[cp+1]==ESC_INTERFACE||
619 basbuf[cp+1]==ESC_ENUM)){
620 GetDefaultNameFromES(basbuf[cp+1],temp3);
621 SetError(12,temp3,cp);
622 }
623 }
624 }
625 if(basbuf[cp]=='\0'){
626 //error
627 //既にエラー発行済みのため、何もせずに抜ける
628 break;
629 }
630 }
631 if(basbuf[cp+2]=='\0'||basbuf[cp]=='\0') break;
632 cp+=2;
633 i2=-1;
634 continue;
635 }
636
637 if(Command[0]==0x10||Command[0]==0x11){
638 //Wend、Next、Loopなど
639 if(Return_Command==MAKEWORD(Command[1],Command[0])){
640 if(Return_Command==COM_NEXT){
641 //Nextの場合は、パラメータ(省略化)の整合性を判断する必要がある(OpcodeFor関数を参照)
642 extern char szNextVariable[VN_SIZE];
643 if(Command[2]) lstrcpy(szNextVariable,Command+2);
644 else szNextVariable[0]=0;
645 }
646 break;
647 }
648 }
649
650 NextLine();
651
652 if(Command[0]==1){
653 if(Return_Sequence==ESC_ENDIF&&Command[1]==ESC_ELSE){
654 dwRetCode=ESC_ELSE;
655 break;
656 }
657
658 if(Command[1]==Return_Sequence){
659 dwRetCode=Command[1];
660 break;
661 }
662 }
663
664 try
665 {
666 ChangeOpcode(Command);
667 }
668 catch( const SmoothieException &smoothieException )
669 {
670 SetError(
671 smoothieException.GetErrorCode(),
672 smoothieException.GetKeyword(),
673 smoothieException.GetNowLine()
674 );
675 }
676
677
678 epi_check();
679
680
681 //コンパイルを中断するとき
682 extern BOOL bStopCompile;
683 if(bStopCompile) return 0;
684
685 ReallocNativeCodeBuffer();
686
687 if(basbuf[cp]=='\0'){
688 switch(Return_Command){
689 case COM_WEND:
690 SetError(4,"\"While\" - \"Wend\" ",ScopeStart);
691 break;
692 case COM_NEXT:
693 SetError(4,"\"For\" - \"Next\" ",ScopeStart);
694 break;
695 case COM_LOOP:
696 SetError(4,"\"Do\" - \"Loop\" ",ScopeStart);
697 break;
698 }
699 switch(Return_Sequence){
700 case ESC_ENDSUB:
701 SetError(4,"\"Sub\" - \"End Sub\" ",ScopeStart);
702 break;
703 case ESC_ENDFUNCTION:
704 SetError(4,"\"Function\" - \"End Function\" ",ScopeStart);
705 break;
706 case ESC_ENDMACRO:
707 SetError(4,"\"Macro\" - \"End Macro\" ",ScopeStart);
708 break;
709 case ESC_ENDIF:
710 SetError(22,"If",ScopeStart);
711 break;
712 }
713 break;
714 }
715 i2=-1;
716 continue;
717 }
718 Command[i2]=basbuf[cp];
719 }
720 HeapDefaultFree(Command);
721
722 return dwRetCode;
723}
Note: See TracBrowser for help on using the repository browser.