This commit is contained in:
Basile Burg 2014-07-01 11:48:52 +02:00
parent 9529b65b4d
commit 24fba590fa
10 changed files with 1088 additions and 163 deletions

View File

@ -128,7 +128,7 @@
<PackageName Value="LCL"/> <PackageName Value="LCL"/>
</Item5> </Item5>
</RequiredPackages> </RequiredPackages>
<Units Count="15"> <Units Count="17">
<Unit0> <Unit0>
<Filename Value="coedit.lpr"/> <Filename Value="coedit.lpr"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
@ -228,6 +228,16 @@
<ResourceBaseClass Value="Form"/> <ResourceBaseClass Value="Form"/>
<UnitName Value="ce_search"/> <UnitName Value="ce_search"/>
</Unit14> </Unit14>
<Unit15>
<Filename Value="..\src\ce_dlang.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="ce_dlang"/>
</Unit15>
<Unit16>
<Filename Value="..\src\ce_dlangutils.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="ce_dlangutils"/>
</Unit16>
</Units> </Units>
</ProjectOptions> </ProjectOptions>
<CompilerOptions> <CompilerOptions>

View File

@ -9,7 +9,7 @@ uses
Interfaces, Forms, lazcontrols, runtimetypeinfocontrols, ce_widget, Interfaces, Forms, lazcontrols, runtimetypeinfocontrols, ce_widget,
ce_dmdwrap, ce_common, ce_synmemo, ce_main, ce_messages, ce_editor, ce_dmdwrap, ce_common, ce_synmemo, ce_main, ce_messages, ce_editor,
ce_projinspect, ce_projconf, jsonparser, ce_project, ce_projinspect, ce_projconf, jsonparser, ce_project,
ce_widgettypes, ce_staticexplorer, ce_search; ce_widgettypes, ce_staticexplorer, ce_search, ce_dlang, ce_dlangutils;
{$R *.res} {$R *.res}

View File

@ -6,7 +6,8 @@ interface
uses uses
Classes, SysUtils, Graphics, Classes, SysUtils, Graphics,
SynEditHighlighter, SynEditHighlighterFoldBase, SynEditTypes; SynEditHighlighter, SynEditHighlighterFoldBase, SynEditTypes,
ce_dlangutils;
const const
@ -152,95 +153,6 @@ type
implementation implementation
function isWhite(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
result := c in [#0..#32];
end;
function isSpace(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
result := c in [#9,' '];
end;
function isAlpha(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
result := (c in ['a'..'z']) or (c in ['A'..'Z']);
end;
function isNumber(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
result := (c in ['0'..'9']);
end;
function isDigit(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
result := (c in ['0'..'1']);
end;
function isAlNum(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
result := isAlpha(c) or isNumber(c);
end;
function isHex(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
result := isNumber(c) or (c in ['A'..'F']) or (c in ['a'..'f']);
end;
function isSymbol(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
result := c in [';', '{', '}', '(', ')', '[', ']', ',', '.', ':' , '"', #39, '?'];
end;
function isOperator(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
result := c in ['/', '*', '-', '+', '%', '>', '<', '=', '!',
'&', '|', '^', '~', '$'];
end;
function isDoubleOperator(const s: string): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
result := false;
case s[1] of
'.': result := (s[2] = '.');
'>': result := s[2] in ['>', '='];
'<': result := s[2] in ['<', '=', '>'];
'=': result := s[2] in ['=', '>'];
'!': result := s[2] in ['=', '>', '<'];
'+': result := s[2] in ['+', '='];
'-': result := s[2] in ['-', '='];
'/': result := s[2] in ['='];
'*': result := s[2] in ['='];
'%': result := s[2] in ['='];
'~': result := s[2] in ['='];
'&': result := s[2] in ['&', '='];
'|': result := s[2] in ['|', '='];
'^': result := s[2] in ['^', '='];
end;
end;
function isTripleOperator(const s: string): boolean; {$IFNDEF DEBUG} inline; {$ENDIF}
begin
result := false;
case s[1] of
'.': result := (s[2] = '.') and (s[3] = '.');
'^': result := (s[2] = '^') and (s[3] = '=');
'>': result := (s[2] = '>') and (s[3] in ['>', '=']);
'<': result := ((s[2] = '<') and (s[3] in ['<', '=']))
or (s[2] = '>') and (s[3] = '=');
'!': result := ((s[2] = '<') and (s[3] in ['>', '=']))
or ((s[2] = '>')and (s[3] = '='));
end;
end;
function isQuadOperator(const s: string): boolean; {$IFNDEF DEBUG} inline; {$ENDIF}
begin
result := (s = '>>>=') or (s = '!<>=');
end;
{$IFDEF USE_DICT_LINKEDCHARMAP} {$IFDEF USE_DICT_LINKEDCHARMAP}
constructor TD2Dictionary.create; constructor TD2Dictionary.create;
var var
@ -526,6 +438,7 @@ TODO:
- string literals: escape bug: std.path/std.regex: "\\" - string literals: escape bug: std.path/std.regex: "\\"
- comments: correct nested comments handling. - comments: correct nested comments handling.
} }
{$BOOLEVAL ON}
procedure TSynD2Syn.next; procedure TSynD2Syn.next;
label label
_postString1; _postString1;
@ -670,7 +583,7 @@ begin
fRange := rkNone; fRange := rkNone;
readNext; readNext;
// check postfix // check postfix
if readCurr in ['c','w','d'] then if isStringPostfix(readCurr) then
readNext; readNext;
exit; exit;
end; end;
@ -679,7 +592,7 @@ begin
begin begin
if fRange = rkNone then if fRange = rkNone then
begin begin
// check hex/WYSIWYG prefix // check WYSIWYG/hex prefix
if readCurr in ['r','x'] then if readCurr in ['r','x'] then
begin begin
if not (readNext = '"') then if not (readNext = '"') then
@ -695,7 +608,7 @@ begin
begin begin
readNext; readNext;
// check postfix // check postfix
if readCurr in ['c','w','d'] then if isStringPostfix(readCurr) then
readNext; readNext;
end; end;
fTokKind := tkStrng; fTokKind := tkStrng;
@ -720,7 +633,7 @@ begin
fRange := rkNone; fRange := rkNone;
readNext; readNext;
// check postfix // check postfix
if readCurr in ['c','w','d'] then if isStringPostfix(readCurr) then
readNext; readNext;
exit; exit;
end; end;
@ -736,7 +649,7 @@ begin
begin begin
readNext; readNext;
// check postfix // check postfix
if readCurr in ['c','w','d'] then if isStringPostfix(readCurr) then
readNext; readNext;
end; end;
fTokKind := tkStrng; fTokKind := tkStrng;
@ -778,30 +691,30 @@ begin
end; end;
// symbols 2: operators // symbols 2: operators
if isOperator(readCurr) then if isOperator1(readCurr) then
begin begin
fTokKind := tkSymbl; fTokKind := tkSymbl;
while isOperator(readNext) do (*!*); while isOperator1(readNext) do (*!*);
case fTokStop - fTokStart of case fTokStop - fTokStart of
1:begin 1:begin
if not isOperator(readCurr) then exit if not isOperator1(readCurr) then exit
else Dec(fTokStop); else Dec(fTokStop);
end; end;
2:begin 2:begin
if (not isOperator(readCurr)) and if (not isOperator1(readCurr)) and
isDoubleOperator(fLineBuf[fTokStart..fTokStop-1]) isOperator2(fLineBuf[fTokStart..fTokStop-1])
then exit then exit
else Dec(fTokStop, 2); else Dec(fTokStop, 2);
end; end;
3:begin 3:begin
if (not isOperator(readCurr)) and if (not isOperator1(readCurr)) and
isTripleOperator(fLineBuf[fTokStart..fTokStop-1]) isOperator3(fLineBuf[fTokStart..fTokStop-1])
then exit then exit
else Dec(fTokStop, 3); else Dec(fTokStop, 3);
end; end;
4:begin 4:begin
if (not isOperator(readCurr)) and if (not isOperator1(readCurr)) and
isQuadOperator(fLineBuf[fTokStart..fTokStop-1]) isOperator4(fLineBuf[fTokStart..fTokStop-1])
then exit then exit
else Dec(fTokStop, 4); else Dec(fTokStop, 4);
end; end;
@ -817,7 +730,7 @@ begin
begin begin
if isWhite(readNext) then break; if isWhite(readNext) then break;
if isSymbol(readCurr) then break; if isSymbol(readCurr) then break;
if isOperator(readCurr) then break; if isOperator1(readCurr) then break;
end; end;
if fKeyWords.find(fLineBuf[FTokStart..fTokStop-1]) then if fKeyWords.find(fLineBuf[FTokStart..fTokStop-1]) then
fTokKind := tkKeywd fTokKind := tkKeywd
@ -832,6 +745,7 @@ begin
// Should not happend // Should not happend
assert(false); assert(false);
end; end;
{$BOOLEVAL OFF}
function TSynD2Syn.GetEol: Boolean; function TSynD2Syn.GetEol: Boolean;
begin begin

831
src/ce_dlang.pas Normal file
View File

@ -0,0 +1,831 @@
unit ce_dlang;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, ce_dlangutils;
const
D2Kw: array[0..109] of string =
( 'abstract', 'alias', 'align', 'asm', 'assert', 'auto',
'body', 'bool', 'break', 'byte',
'case', 'cast', 'catch', 'cdouble', 'cent', 'cfloat', 'char', 'class',
'const', 'continue', 'creal',
'dchar', 'debug', 'default', 'delegate', 'delete', 'deprecated', 'do', 'double',
'else', 'enum', 'export', 'extern',
'false', 'final', 'finally', 'float', 'for', 'foreach',
'foreach_reverse', 'function',
'goto',
'idouble', 'if', 'ifloat', 'immutable', 'import', 'in', 'inout', 'int',
'interface', 'invariant', 'ireal', 'is',
'lazy', 'long',
'macro', 'mixin', 'module',
'new', 'nothrow', 'null',
'out', 'override',
'package', 'pragma', 'private', 'protected', 'ptrdiff_t', 'public', 'pure',
'real', 'ref', 'return',
'size_t', 'scope', 'shared', 'short', 'static', 'string', 'struct',
'super', 'switch', 'synchronized',
'template', 'this', 'throw', 'true', 'try', 'typedef', 'typeid', 'typeof',
'ubyte', 'ucent', 'uint', 'ulong', 'union', 'unittest', 'ushort',
'version', 'void', 'volatile',
'wchar', 'while', 'with',
'__FILE__', '__MODULE__', '__LINE__', '__FUNCTION__', '__PRETTY_FUNCTION__'
);
type
(**
* sector for an array of Keyword with a common hash.
*)
TD2DictionaryEntry = record
filled: Boolean;
values: array of string;
end;
(**
* Dictionary for the D2 keywords.
*)
TD2Dictionary = object
private
fLongest, fShortest: NativeInt;
fEntries: array[Byte] of TD2DictionaryEntry;
function toHash(const aValue: string): Byte; {$IFNDEF DEBUG}inline;{$ENDIF}
procedure addEntry(const aValue: string);
public
constructor create;
destructor destroy; // do not remove even if empty (compat with char-map version)
function find(const aValue: string): boolean;
end;
(**
* Represents the pointer in a source file.
* Automatically updates the line and the column.
*)
TReaderHead = object
private
fLineIndex: Integer;
fColumnIndex: Integer;
fAbsoluteIndex: Integer;
fReaderHead: PChar;
function getColAndLine: TPoint;
public
constructor create(const aText: PChar; const aColAndLine: TPoint);
procedure setReader(const aText: PChar; const aColAndLine: TPoint);
//
function next: PChar;
function previous: PChar;
//
property AbsoluteIndex: Integer read fAbsoluteIndex;
property LineIndex: Integer read fLineIndex;
property ColumnIndex: Integer read fColumnIndex;
property LineAnColumn: TPoint read getColAndLine;
//
property head: PChar read fReaderHead;
end;
TLexTokenKind = (ltkIllegal, ltkChar, ltkComment, ltkIdentifier, ltkKeyword,
ltkNumber, ltkOperator, ltkString, ltkSymbol);
const
LexTokenKindString : array[TLexTokenKind] of string =
( 'Illegal', 'Character', 'Comment', 'Identifier', 'Keyword',
'Number', 'Operator', 'String', 'Symbol');
type
(*****************************************************************************
* Lexer token
*)
PLexToken = ^TLexToken;
TLexToken = record
position: TPoint;
kind: TLexTokenKind;
data: string;
end;
(*****************************************************************************
* List of lexer tokens
*)
TLexTokenList = class(TList)
private
function getToken(index: integer): TLexToken;
public
procedure clear; override;
procedure addToken(aValue: PLexToken);
property token[index: integer]: TLexToken read getToken;
end;
TLexTokenEnumerator = class
fList: TLexTokenList;
fIndex: Integer;
function GetCurrent: TLexToken;
function MoveNext: Boolean;
property Current: TLexToken read GetCurrent;
end;
(*****************************************************************************
* Error record
*)
PLexError = ^TLexError;
TLexError = record
position: TPoint;
msg: string;
end;
(*****************************************************************************
* Error list
*)
TLexErrorList = class(TList)
private
function getError(index: integer): TLexError;
public
procedure clear; override;
procedure addError(aValue: PLexError);
property error[index: integer]: TLexError read getError;
end;
TLexErrorEnumerator = class
fList: TLexErrorList;
fIndex: Integer;
function GetCurrent: TLexError;
function MoveNext: Boolean;
property Current: TLexError read GetCurrent;
end;
operator enumerator(aTokenList: TLexTokenList): TLexTokenEnumerator;
operator enumerator(anErrorList: TLexErrorList): TLexErrorEnumerator;
(*****************************************************************************
* Lexes aText and fills aList with the TLexToken found.
*)
procedure lex(const aText: string; const aList: TLexTokenList);
(*****************************************************************************
* Detects various syntaxic error in a TLexTokenList
*)
procedure checkSyntaxicErrors(const aTokenList: TLexTokenList; const anErrorList: TLexErrorList);
(*****************************************************************************
* Compares two TPoints.
*)
operator = (lhs: TPoint; rhs: TPoint): boolean;
implementation
var
D2Dictionary: TD2Dictionary;
{$REGION TReaderHead------------------------------------------------------------}
operator = (lhs: TPoint; rhs: TPoint): boolean;
begin
exit( (lhs.y = rhs.y) and (lhs.x = rhs.x) );
end;
constructor TReaderHead.create(const aText: PChar; const aColAndLine: TPoint);
begin
setReader(aText,aColAndLine);
end;
procedure TReaderHead.setReader(const aText: PChar; const aColAndLine: TPoint);
begin
fLineIndex := aColAndLine.y;
fColumnIndex := aColAndLine.x;
fReaderHead := aText;
while (LineAnColumn <> aColAndLine) do next;
//
// editor not 0 based ln index
if fLineIndex = 0 then fLineIndex := 1;
end;
function TReaderHead.getColAndLine: TPoint;
begin
exit( Point(fColumnIndex, fLineIndex) );
end;
function TReaderHead.next: PChar;
begin
Inc(fReaderHead);
Inc(fAbsoluteIndex);
Inc(fColumnIndex);
if (fReaderHead^ = #10) then
begin
Inc(fLineIndex);
fColumnIndex := 0;
end;
exit(fReaderHead);
end;
function TReaderHead.previous: PChar;
begin
// note: it breaks the column but not the line count
Dec(fReaderHead);
Dec(fColumnIndex);
Dec(fAbsoluteIndex);
exit(fReaderHead);
end;
{$ENDREGION}
{$REGION TD2Dictionary----------------------------------------------------------}
constructor TD2Dictionary.create;
var
value: string;
begin
for value in D2Kw do
addEntry(value);
end;
destructor TD2Dictionary.destroy;
begin
end;
{$IFDEF DEBUG}{$R-}{$ENDIF}
function TD2Dictionary.toHash(const aValue: string): Byte;
var
i: Integer;
begin
result := 0;
for i := 1 to length(aValue) do result +=
(Byte(aValue[i]) shl (4 and (1-i))) xor 25;
end;
{$IFDEF DEBUG}{$R+}{$ENDIF}
procedure TD2Dictionary.addEntry(const aValue: string);
var
hash: Byte;
begin
if find(aValue) then exit;
hash := toHash(aValue);
fEntries[hash].filled := true;
setLength(fEntries[hash].values, length(fEntries[hash].values) + 1);
fEntries[hash].values[high(fEntries[hash].values)] := aValue;
if fLongest <= length(aValue) then
fLongest := length(aValue);
if fShortest >= length(aValue) then
fShortest := length(aValue);
end;
function TD2Dictionary.find(const aValue: string): boolean;
var
hash: Byte;
i: NativeInt;
begin
result := false;
if length(aValue) > fLongest then exit;
if length(aValue) < fShortest then exit;
hash := toHash(aValue);
if (not fEntries[hash].filled) then exit(false);
for i:= 0 to high(fEntries[hash].values) do
if fEntries[hash].values[i] = aValue then exit(true);
end;
{$ENDREGION}
{$REGION Lexing-----------------------------------------------------------------}
function TLexTokenList.getToken(index: integer): TLexToken;
begin
result := PLexToken(Items[index])^;
end;
procedure TLexTokenList.clear;
begin
while Count > 0 do
begin
Dispose( PLexToken(Items[Count-1]) );
Delete(Count-1);
end;
end;
procedure TLexTokenList.addToken(aValue: PLexToken);
begin
add(Pointer(aValue));
end;
function TLexTokenEnumerator.GetCurrent: TLexToken;
begin
exit(fList.token[fIndex]);
end;
function TLexTokenEnumerator.MoveNext: Boolean;
begin
Inc(fIndex);
exit(fIndex < fList.Count);
end;
operator enumerator(aTokenList: TLexTokenList): TLexTokenEnumerator;
begin
result := TLexTokenEnumerator.Create;
result.fList := aTokenList;
result.fIndex := -1;
end;
{$BOOLEVAL ON}
procedure lex(const aText: string; const aList: TLexTokenList);
var
reader: TReaderHead;
identifier: string;
function isOutOfBound: boolean;
begin
exit(reader.AbsoluteIndex > length(aText))
end;
procedure addToken(aTk: TLexTokenKind);
var
ptk: PLexToken;
begin
ptk := new(PLexToken);
ptk^.kind := aTk;
ptk^.position := reader.LineAnColumn;
ptk^.data := identifier;
aList.Add(ptk);
end;
begin
reader.create(@aText[1], Point(0,0));
while (true) do
begin
if isOutOfBound then
exit;
identifier := '';
// skip blanks
while isWhite(reader.head^) do
begin
reader.next;
if isOutOfBound then exit;
end;
// line comment
if (reader.head^ = '/') then
begin
if (reader.next^ = '/') then
begin
if isOutOfBound then exit;
while (reader.head^ <> #10) do
begin
reader.next;
identifier += reader.head^;
if isOutOfBound then exit;
end;
reader.next;
addToken(ltkComment);
continue;
end
else
reader.previous;
end;
// block comments 1
if (reader.head^ = '/') then
begin
if (reader.next^ = '*') then
begin
if isOutOfBound then exit;
while (reader.head^ <> '*') or (reader.next^ <> '/') do
if isOutOfBound then exit;
reader.next;
addToken(ltkComment);
continue;
end
else
reader.previous;
end;
// block comments 2
if (reader.head^ = '/') then
begin
if (reader.next^ = '+') then
begin
if isOutOfBound then exit;
while (reader.head^ <> '+') or (reader.next^ <> '/') do
if isOutOfBound then exit;
reader.next;
addToken(ltkComment);
continue;
end
else
reader.previous;
end;
// string 1, note: same escape error as in SynD2Syn
if (reader.head^ in ['r', 'x']) then
begin
if not (reader.next^ = '"') then
reader.previous;
end;
if (reader.head^ = '"') then
begin
reader.next;
if isOutOfBound then exit;
if (reader.head^ = '"') then
begin
reader.next;
addToken(ltkString);
continue;
end;
while (true) do
begin
if reader.head^ = '\' then
begin
reader.next;
if (reader.head^ = '"') then
begin
reader.next;
continue;
end;
end;
if (reader.head^ = '"') then
break;
identifier += reader.head^;
reader.next;
if isOutOfBound then exit;
end;
if isStringPostfix(reader.next^) then
reader.next;
addToken(ltkString);
continue;
end;
// string 2
if (reader.head^ = '`') then
begin
reader.next;
if isOutOfBound then exit;
while (reader.head^ <> '`') do
begin
identifier += reader.head^;
reader.next;
if isOutOfBound then exit;
end;
if isStringPostfix(reader.next^) then
reader.next;
if isOutOfBound then exit;
addToken(ltkString);
continue;
end;
//chars, note: same escape error as in SynD2Syn
if (reader.head^ = #39) then
begin
reader.next;
if isOutOfBound then exit;
if (reader.head^ = #39) then
begin
reader.next;
addToken(ltkString);
continue;
end;
while (true) do
begin
if reader.head^ = '\' then
begin
reader.next;
if (reader.head^ = #39) then
begin
reader.next;
continue;
end;
end;
if (reader.head^ = #39) then
break;
identifier += reader.head^;
reader.next;
if isOutOfBound then exit;
end;
reader.next;
addToken(ltkChar);
continue;
end;
// check negative float '-0.'
if (reader.head^ = '-') then
begin
identifier += reader.head^;
if reader.next^ = '0' then
begin
if reader.next^ = '.' then
reader.previous // back to 0, get into "binary/hex numbr/float"
else
begin
reader.previous;
reader.previous; // back to -
identifier := '';
end;
end
else
begin
reader.previous; // back to -
identifier := '';
end;
end;
// + suffixes
// + exponent
// float .xxxx
// binary/hex numbr/float
if (reader.head^ = '0') then
begin
identifier += reader.head^;
if (reader.next^ in ['b','B']) then
begin
identifier += reader.head^;
while isBit(reader.next^) or (reader.head^ = '_') do
begin
if isOutOfBound then exit;
identifier += reader.head^;
end;
addToken(ltkNumber);
continue;
end
else reader.previous;
if (reader.next^ in ['x','X']) then
begin
identifier += reader.head^;
while isHex(reader.next^) or (reader.head^ = '_') do
begin
if isOutOfBound then exit;
identifier += reader.head^;
end;
addToken(ltkNumber);
continue;
end
else reader.previous;
if (reader.next^ = '.') then
begin
identifier += reader.head^;
while isNumber(reader.next^) do
begin
if isOutOfBound then exit;
identifier += reader.head^;
end;
addToken(ltkNumber);
continue;
end
else reader.previous;
identifier := '';
end;
// check negative float/int '-xxx'
if (reader.head^ = '-') then
begin
identifier += reader.head^;
if not isNumber(reader.next^) then
begin
reader.previous; // back to '-'
identifier := '';
end;
end;
// numbers
if isNumber(reader.head^) then
begin
identifier += reader.head^;
while isNumber(reader.next^) or (reader.head^ = '_') do
begin
if isOutOfBound then exit;
identifier += reader.head^;
end;
addToken(ltkNumber);
continue;
end;
// symbols
if isSymbol(reader.head^) then
begin
identifier += reader.head^;
reader.next;
addToken(ltkSymbol);
if isOutOfBound then exit;
continue;
end;
// operators
if isOperator1(reader.head^) then
begin
identifier += reader.head^;
while isOperator1(reader.next^) do
begin
if isOutOfBound then exit;
identifier += reader.head^;
end;
case length(identifier) of
4:begin
if (not isOperator1(reader.head^)) and
isOperator4(identifier) then
begin
addToken(ltkOperator);
continue;
end;
end;
3:begin
if (not isOperator1(reader.head^)) and
isOperator3(identifier) then
begin
addToken(ltkOperator);
continue;
end;
end;
2:begin
if (not isOperator1(reader.head^)) and
isOperator2(identifier) then
begin
addToken(ltkOperator);
continue;
end;
end;
1:begin
if not isOperator1(reader.head^)
then
begin
addToken(ltkOperator);
continue;
end;
end;
end;
end;
// identifier accum
if isFirstIdentifier(reader.head^) then
begin
while isIdentifier(reader.head^) do
begin
identifier += reader.head^;
reader.next;
if isOutOfBound then exit;
end;
if D2Dictionary.find(identifier) then
addToken(ltkKeyword)
else
addToken(ltkIdentifier);
continue;
end;
// error
identifier += ' (unrecognized lexer input)';
addToken(ltkIllegal);
end;
end;
{$BOOLEVAL OFF}
{$ENDREGION}
{$REGION Syntaxic errors}
function TLexErrorList.getError(index: integer): TLexError;
begin
result := PLexError(Items[index])^;
end;
procedure TLexErrorList.clear;
begin
while Count > 0 do
begin
Dispose( PLexError(Items[Count-1]) );
Delete(Count-1);
end;
end;
procedure TLexErrorList.addError(aValue: PLexError);
begin
add(Pointer(aValue));
end;
function TLexErrorEnumerator.GetCurrent: TLexError;
begin
exit(fList.error[fIndex]);
end;
function TLexErrorEnumerator.MoveNext: Boolean;
begin
Inc(fIndex);
exit(fIndex < fList.Count);
end;
operator enumerator(anErrorList: TLexErrorList): TLexErrorEnumerator;
begin
result := TLexErrorEnumerator.Create;
result.fList := anErrorList;
result.fIndex := -1;
end;
procedure checkSyntaxicErrors(const aTokenList: TLexTokenList; const anErrorList: TLexErrorList);
const
errPrefix = 'syntaxic error: ';
var
tk, old1, old2: TLexToken;
err: PLexError;
tkIndex: NativeInt;
pareCnt, curlCnt, squaCnt: NativeInt;
procedure addError(const aMsg: string);
begin
err := new(PLexError);
err^.msg := errPrefix + aMsg;
err^.position := aTokenList.token[tkIndex].position;
anErrorList.addError(err);
end;
label
_preSeq;
begin
tkIndex := -1;
pareCnt := 0;
curlCnt := 0;
squaCnt := 0;
for tk in aTokenList do
begin
// token index
Inc(tkIndex);
// brackets count
if tk.kind = ltkSymbol then
begin
case tk.data of
'(': Inc(pareCnt);
'{': Inc(curlCnt);
'[': Inc(squaCnt);
')': Dec(pareCnt);
'}': Dec(curlCnt);
']': Dec(squaCnt);
end;
// only for the first occurence
if pareCnt = -1 then
addError('a left parenthesis is missing');
if curlCnt = -1 then
addError('a left curly bracket is missing');
if squaCnt = -1 then
addError('a left square bracket is missing');
// at the end
if (tkIndex = aTokenList.Count-1) then
begin
if pareCnt > 0 then
addError('a right parenthesis is missing');
if curlCnt > 0 then
addError('a right curly bracket is missing');
if squaCnt > 0 then
addError('a right square bracket is missing');
end;
goto _preSeq;
end;
// lexer invalid token
if tk.kind = ltkIllegal then
begin
addError(tk.data);
goto _preSeq;
end;
// invalid numbers
if tk.kind = ltkNumber then
begin
goto _preSeq;
end;
_preSeq:
// invalid sequences
if tkIndex > 0 then // can use old1
begin
if (old1.kind = ltkKeyword) and (tk.kind = ltkKeyword) then
if old1.data = tk.data then
addError('keyword is duplicated');
// needs negative numbr to be tokenized correctly: ... = -1; '-' is currently token as an operator.
if (old1.kind = ltkOperator) and (tk.kind = ltkOperator) then
addError('operator rhs cannot be an operator');
if (old1.kind = ltkNumber) and (tk.kind = ltkNumber) then
addError('symbol or operator expected after number');
end;
if tkIndex > 1 then // can use old2
begin
end;
old1 := tk;
old2 := old1;
end;
end;
{$ENDREGION}
initialization
D2Dictionary.create;
finalization
D2Dictionary.destroy;
end.

135
src/ce_dlangutils.pas Normal file
View File

@ -0,0 +1,135 @@
unit ce_dlangutils;
{$mode objfpc}{$H+}
interface
uses
SysUtils;
function isWhite(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
function isSpace(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
function isAlpha(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
function isNumber(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
function isBit(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
function isAlNum(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
function isHex(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
function isSymbol(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
function isOperator1(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
function isOperator2(const s: string): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
function isOperator3(const s: string): boolean; {$IFNDEF DEBUG} inline; {$ENDIF}
function isOperator4(const s: string): boolean; {$IFNDEF DEBUG} inline; {$ENDIF}
function isStringPostfix(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
function isIdentifier(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
function isFirstIdentifier(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
implementation
{$BOOLEVAL ON}
function isWhite(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
exit(c in [#0..#32]);
end;
function isSpace(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
exit(c in [#9,' ']);
end;
function isAlpha(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
exit((c in ['a'..'z']) or (c in ['A'..'Z']));
end;
function isNumber(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
exit(c in ['0'..'9']);
end;
function isBit(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
exit((c in ['0'..'1']));
end;
function isAlNum(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
exit(isAlpha(c) or isNumber(c));
end;
function isHex(const c: Char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
exit(isNumber(c) or (c in ['A'..'F']) or (c in ['a'..'f']));
end;
function isSymbol(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
exit(c in [';', '{', '}', '(', ')', '[', ']', ',', '.', ':' , '"', #39, '?', '$']);
end;
function isOperator1(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
exit(c in ['/', '*', '-', '+', '%', '>', '<', '=', '!',
'&', '|', '^', '~']);
end;
function isOperator2(const s: string): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
result := false;
case s[1] of
'.': result := (s[2] = '.');
'>': result := s[2] in ['>', '='];
'<': result := s[2] in ['<', '=', '>'];
'=': result := s[2] in ['=', '>'];
'!': result := s[2] in ['=', '>', '<'];
'+': result := s[2] in ['+', '='];
'-': result := s[2] in ['-', '='];
'/': result := s[2] in ['='];
'*': result := s[2] in ['='];
'%': result := s[2] in ['='];
'~': result := s[2] in ['='];
'&': result := s[2] in ['&', '='];
'|': result := s[2] in ['|', '='];
'^': result := s[2] in ['^', '='];
end;
end;
function isOperator3(const s: string): boolean; {$IFNDEF DEBUG} inline; {$ENDIF}
begin
result := false;
case s[1] of
'.': result := (s[2] = '.') and (s[3] = '.');
'^': result := (s[2] = '^') and (s[3] = '=');
'>': result := (s[2] = '>') and (s[3] in ['>', '=']);
'<': result := ((s[2] = '<') and (s[3] in ['<', '=']))
or (s[2] = '>') and (s[3] = '=');
'!': result := ((s[2] = '<') and (s[3] in ['>', '=']))
or ((s[2] = '>')and (s[3] = '='));
end;
end;
function isOperator4(const s: string): boolean; {$IFNDEF DEBUG} inline; {$ENDIF}
begin
result := (s = '>>>=') or (s = '!<>=');
end;
function isStringPostfix(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
exit(c in ['c', 'w', 'd']);
end;
function isIdentifier(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
exit((not isSymbol(c)) and (not isOperator1(c)) and (not isWhite(c)));
end;
function isFirstIdentifier(const c: char): boolean; {$IFNDEF DEBUG}inline;{$ENDIF}
begin
exit(isIdentifier(c) and (not isNumber(c)));
end;
{$BOOLEVAL OFF}
end.

View File

@ -8,7 +8,8 @@ uses
Classes, SysUtils, FileUtil, ExtendedNotebook, Forms, Controls, lcltype, Classes, SysUtils, FileUtil, ExtendedNotebook, Forms, Controls, lcltype,
Graphics, SynEditKeyCmds, ComCtrls, SynEditHighlighter, ExtCtrls, Menus, Graphics, SynEditKeyCmds, ComCtrls, SynEditHighlighter, ExtCtrls, Menus,
SynEditHighlighterFoldBase, SynMacroRecorder, SynPluginSyncroEdit, SynEdit, SynEditHighlighterFoldBase, SynMacroRecorder, SynPluginSyncroEdit, SynEdit,
SynHighlighterLFM, ce_widget, ce_d2syn, ce_synmemo, ce_common, AnchorDocking; SynHighlighterLFM, ce_widget, ce_d2syn, ce_synmemo, ce_common, AnchorDocking,
ce_dlang;
type type
{ TCEEditorWidget } { TCEEditorWidget }
@ -26,7 +27,6 @@ type
fKeyChanged: boolean; fKeyChanged: boolean;
fSyncEdit: TSynPluginSyncroEdit; fSyncEdit: TSynPluginSyncroEdit;
procedure memoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure memoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure memoKeyPress(Sender: TObject; var Key: Char);
procedure memoMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure memoMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure memoChange(Sender: TObject); procedure memoChange(Sender: TObject);
procedure memoMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure memoMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
@ -138,7 +138,6 @@ begin
memo.OnMouseDown := @memoMouseDown; memo.OnMouseDown := @memoMouseDown;
memo.OnChange := @memoChange; memo.OnChange := @memoChange;
memo.OnMouseMove := @memoMouseMove; memo.OnMouseMove := @memoMouseMove;
memo.OnKeyPress := @memoKeyPress;
// //
pageControl.ActivePage := sheet; pageControl.ActivePage := sheet;
//http://bugs.freepascal.org/view.php?id=26320 //http://bugs.freepascal.org/view.php?id=26320
@ -158,15 +157,13 @@ end;
procedure TCEEditorWidget.memoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure TCEEditorWidget.memoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin begin
end; if (sender is TCESynMemo) then
procedure TCEEditorWidget.memoKeyPress(Sender: TObject; var Key: Char);
begin
if (sender is TCESynMemo) then
identifierToD2Syn(TCESynMemo(Sender)); identifierToD2Syn(TCESynMemo(Sender));
fKeyChanged := true;
case Byte(Key) of case Byte(Key) of
VK_UNKNOWN..VK_BACK: exit; VK_UNKNOWN..VK_XBUTTON2: exit;
VK_PRIOR..VK_HELP: exit; VK_SHIFT..VK_HELP: fKeyChanged := false;
VK_LWIN..VK_SLEEP: exit;
VK_F1..$91: exit; VK_F1..$91: exit;
end; end;
fKeyChanged := true; fKeyChanged := true;
@ -200,6 +197,9 @@ const
modstr: array[boolean] of string = ('...', 'MODIFIED'); modstr: array[boolean] of string = ('...', 'MODIFIED');
var var
ed: TCESynMemo; ed: TCESynMemo;
tokLst: TLexTokenList;
errLst: TLexErrorList;
err: TLexError;
begin begin
ed := getCurrentEditor; ed := getCurrentEditor;
if ed <> nil then if ed <> nil then
@ -210,8 +210,31 @@ begin
end; end;
// //
if fKeyChanged then if editorIndex <> -1 then if fKeyChanged then if editorIndex <> -1 then
begin
mainForm.docChangeNotify(Self, editorIndex); mainForm.docChangeNotify(Self, editorIndex);
mainForm.MessageWidget.List.Clear;
tokLst := TLexTokenList.Create;
errLst := TLexErrorList.Create;
try
lex( ed.Lines.Text, tokLst );
checkSyntaxicErrors( tokLst, errLst);
for err in errLst do
mainForm.MessageWidget.addMessage(format(
'%s (@line:%4.d @char:%.4d)',[err.msg, err.position.y, err.position.x]));
mainForm.MessageWidget.scrollToBack;
finally
tokLst.Free;
errLst.Free;
end;
end;
fKeyChanged := false; fKeyChanged := false;
end; end;
end. end.

View File

@ -2547,39 +2547,39 @@ object CEMainForm: TCEMainForm
0000000000330000003300000033000000332D73BAAF1B3D60523F93D4FF3F93 0000000000330000003300000033000000332D73BAAF1B3D60523F93D4FF3F93
D4FF102438413578BAC300000024000000000000000000000000000000000000 D4FF102438413578BAC300000024000000000000000000000000000000000000
0000000000000000000000000000000000000000001F00000008000000330000 0000000000000000000000000000000000000000001F00000008000000330000
0033000000040000002400000000B3B3B1EFB0B0ADFFAEAEACFFAEAEABFFAEAE 0033000000040000002400000000BB871F00BB871F00BB871E00B9841A00B67E
ABFFAEAEABFFADAEABFFAEAEABFFAFAFADFFB0B0AEEAB3B3B100B5B5B300B5B5 0FEAC4973BFFC79D49FFC39538FFB37904FFB47A07FFB47A07FFB47A08FFB57C
B300B5B5B300B5B5B300B5B5B300AFAFADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 0AFFB67F0FFFB88114FFBA851B23BB871F00BB871F00BA861D00B7801283E4CF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9E9E9FFAEAEACA6B3B3B100B5B5 A7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
B300B5B5B300B5B5B300B5B5B300AEAEACFFFFFFFFFFE0DFDEFFE1DFDEFFE1E0 FFFFE9DABAFFEEE2C9FFB67F14BFBB871F00BB871F00B9851B00B27A09E5FFFF
DFFFE1DFDEFFE0DFDEFFFFFFFFFFA5A5A3FFFFFFFFFFE8E8E8FFAFAFACA7B3B3 FFFFFFFFFFFFFEFEFBFFFEFEFBFFFEFEFCFFFEFEFCFFFEFEFCFFFFFFFEFFFFFF
B100B5B5B300B5B5B300B6B6B400AEAEABFFFFFFFFFFE3E3E2FFE4E4E3FFE4E5 FFFFC69941FFECDFC2FFC19234FFBB871F00BB871E00B9831800C89E49FFFFFF
E4FFE4E4E3FFE3E3E2FFFFFFFFFFA7A7A5FFECECEBFFFFFFFFFFEAEAEAFFB1B1 FFFFFCF9F3FFFBF8F1FFFBF8F1FFFBF8F1FFFBF8F1FFFCF9F3FFFDFBF6FFFFFF
AFACB6B6B400B8B8B600B9B9B700ADAEABFFFFFFFFFFE7E5E4FFE8E7E6FFE8E7 FFFFB27701FFBA851BFFBC8921FFBB871F00BB861E00B882150CCCA556FFFFFF
E6FFE8E7E6FFE7E6E5FFFFFFFFFFCDCDCCFFAAAAA8FFADADABFFFFFFFFFFB3B3 FFFFF9F6EBFFF9F5EAFFFAF6ECFFFBF7EDFFFDF9EEFFFFFCF1FFFFFFFCFFFFFF
B1FFB8B9B7008A8886008C898700ADADABFFFFFFFFFFE9E9E8FFEAEAE9FFEAEA FFFFAB7405CE0000003300000033BB871F00BB861D00B07B1134DBBF88FFFFFF
E9FFEAEAE9FFECECEBFFFAFAF9FFFFFFFFFFFFFFFFFF7B7976FF7E7B79FFB8B8 FFFFF7F2E5FFFAF4E6FFFEF7E9FFFFF9EAFFFFFCEDFF767574FF777778FFF8E9
B6FF979593008D8B89008F8D8B00ADADABFFFFFFFFFFECEBEAFFEDECEBFFEDEC CAFFAA7200A8888D99008B8E9700BB871F00BA861D00AD790E73EADBBBFFFAF7
EBFFEEEDECFFF3F2F1FF7B7977FF8C8987FFCBCAC8FFB2AFADFFB5B2B0FFA3A3 EEFFF6EFDEFFFCF4E2FF7B797AFF8B8A89FFD2CCBFFFB1AFAEFFB1B1B1FFC3B2
A1FF979593FF8D8B89FF908E8B00ADADABFFFFFFFFFFEFEFEEFFEFEFEEFFEFEF 8EFF939499FF8C8B8EFF8E8E8E00BB871F00BA851C00AA760C9BF0E4CCFFF6EF
EEFFF1F1F0FFF7F8F7FF8B8987FFD8D5D5FF9B9996FFD0CECDFFD1CFCEFF9D9B E0FFF4ECD7FFFAF2DCFF8B8A8AFFD7D6D6FF9A9997FFD0CECEFFD0CFCFFF9C9A
99FFDCDAD9FF918F8DFF94929000ADADABFFFFFFFFFFF2F1F0FFF2F1F0FFF3F1 9AFFDBDADBFF918F8EFF94929000BB871F00BA851C00B0790BD2FFFFFFFFF1E9
F0FFF6F5F4FFFFFEFDFFB6B3B3FF9B9996FFBCBAB9FF92908FFF92908FFFBCBA D2FFF4EBD2FFFCF2D7FFB4AFA2FF9B9997FFBCBABAFF939191FF929191FFBCBA
B9FF9E9C9AFF6C6B699B908E8C00ADADABFFFFFFFFFFF4F4F3FFF4F4F3FFF5F6 BAFF9E9C9AFF6C6B699B908E8C00BB871E00B9841900B8831BEFFFFFFFFFF2E9
F4FFFCFCFBFF73706EFFABA9A8FFCCCAC9FF918F8DFFE1E1E1FFECECEBFF918F D3FFF7EDD4FF747577FFABA9AAFFCCCACAFF92908FFFDCD2B9FFE9E7E2FF918F
8CFFCDCBCBFFB1AFAEFF8F8D8BFFADADABFFFFFFFFFFF6F6F6FFF6F6F6FFF7F8 8EFFCECCCBFFB1AFAEFF8F8D8BFFB98419FFB67E0EFFB67F0FFFC0902EFFC08E
F8FFFEFFFFFF726F6DFFAAA8A7FFCAC8C7FF8E8C8BFFFFFFFFFFFFFFFFFF8E8C 29FFC59128FF747578FFAAA8A9FFCAC8C7FF8F8D8EFFFFF2D2FFFFFFF5FF8F8D
8BFFCBC9C8FFB0AEADFF8E8C8AFFADADABFFFFFFFFFFFAF8F8FFF9F8F8FFFAF9 8DFFCBC9C9FFB0AEADFF8E8C8AFFB78012FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
F9FFFEFDFDFFE1E1E0FFC2C1C0FF959392FFB5B3B2FF8D8B89FF8D8B88FFB5B3 FFFFFFFFFFFFE3E3DFFFC2C1BBFF959493FFB5B3B4FF8D8C8CFF8D8C8BFFB6B4
B2FF999796FF646260894847465BAEAEABFFFFFFFFFFFDFDFDFFFCFCFDFFFCFD B3FF999796FF646260894847465BAC7A14CADCC189FFF5F0E0FFF4EDDBFFF4ED
FDFFFFFFFFFFFFFFFFFF84817FFFCCCAC9FF949291FFC5C3C2FFC6C4C3FF9694 DBFFF6EFDBFFFDF4DCFF878789FFCECDCEFF969698FFC6C5C6FFC7C5C5FF9896
93FFD0CECDFF8B8988FF0000000AB0B0ADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 95FFD1CFCEFF8B8988FF0000000A60440E44B88114FFB67E0FFFB57D0DFFB57D
FFFFFFFFFFFFFFFFFFFF787573FF817E7CFFDDDCDDFFA5A3A2FFA7A5A4FFA4A3 0CFFB67E0CFFBC7F06FF7F8188FF86878AFFA87F2DFFA8A8ABFFAAA8A8FF5250
A1FF878583FF868482FF88868400A4A4A2C0AFAFADFFAEAEABFFADADABFFADAD 4F698A8886FF868482FF88868400000000070000003300000033000000330000
ABFFAEAEACFFB1B1AEFFB6B6B4FFB7B8B6FFB9BAB7FF797776FF7A7877FFADAE 003300000033000000330000003300000033000000337C7C81FF7E7D7DFF0000
ACB9000000330000003388868400000000000000003300000033000000330000 000E000000330000003388868400000000000000000000000000000000000000
0033000000330000003300000033000000330000003300000033000000330000 0000000000000000000000000000000000000000000000000033000000330000
0022000000000000000000000000FFFFFF000000000000000000000000000000 0000000000000000000000000000FFFFFF000000000000000000000000000000
0000000000000000000000000000A6A4A133A5A39FE5AEACA9FFB9B6B5FFABA9 0000000000000000000000000000A6A4A133A5A39FE5AEACA9FFB9B6B5FFABA9
A5FFA7A5A2D2A8A6A323FFFFFF00FFFFFF000000000000000000000000000000 A5FFA7A5A2D2A8A6A323FFFFFF00FFFFFF000000000000000000000000000000
00000000000000000000A19F9C48AEACAAFFDADAD9FFF0EEEFFFECEBEAFFE2E0 00000000000000000000A19F9C48AEACAAFFDADAD9FFF0EEEFFFECEBEAFFE2E0

View File

@ -16,7 +16,7 @@ type
TCEMainForm = class; TCEMainForm = class;
(** (**
* Encapsulates the options. * Encapsulates the options in a writable component.
* note: likely to change however needed to test correctly Coedit. * note: likely to change however needed to test correctly Coedit.
*) *)
TCEOptions = class(TComponent) TCEOptions = class(TComponent)
@ -45,7 +45,7 @@ type
procedure saveToFile(const aFilename: string); procedure saveToFile(const aFilename: string);
procedure loadFromFile(const aFilename: string); procedure loadFromFile(const aFilename: string);
procedure beforeSave; procedure beforeSave;
procedure afterSave; procedure afterLoad;
procedure DefineProperties(Filer: TFiler); override; procedure DefineProperties(Filer: TFiler); override;
end; end;
@ -375,8 +375,8 @@ begin
actEdIndent.Enabled := true; actEdIndent.Enabled := true;
actEdUnIndent.Enabled := true; actEdUnIndent.Enabled := true;
// //
actFileCompAndRun.Enabled := true; actFileCompAndRun.Enabled := curr.isDSource;
actFileCompAndRunWithArgs.Enabled := true; actFileCompAndRunWithArgs.Enabled := curr.isDSource;
actFileSave.Enabled := true; actFileSave.Enabled := true;
actFileSaveAs.Enabled := true; actFileSaveAs.Enabled := true;
actFileClose.Enabled := true; actFileClose.Enabled := true;
@ -694,7 +694,7 @@ var
begin begin
if fEditWidg = nil then exit; if fEditWidg = nil then exit;
if fEditWidg.editorIndex < 0 then exit; if fEditWidg.editorIndex < 0 then exit;
if fEditWidg.editor[fEditWidg.editorIndex].Highlighter = LfmSyn if fEditWidg.editor[fEditWidg.editorIndex].isProjectSource
then exit; then exit;
// //
str := fEditWidg.editor[fEditWidg.editorIndex].fileName; str := fEditWidg.editor[fEditWidg.editorIndex].fileName;
@ -1327,10 +1327,10 @@ begin
except except
exit; exit;
end; end;
afterSave; afterLoad;
end; end;
procedure TCEOptions.afterSave; procedure TCEOptions.afterLoad;
var var
widg: TCEWidget; widg: TCEWidget;
begin begin

View File

@ -15,12 +15,17 @@ type
fFilename: string; fFilename: string;
fModified: boolean; fModified: boolean;
fAssocProject: TCEProject; fAssocProject: TCEProject;
function getIfDSource: Boolean;
function getIfConfig: Boolean;
public public
constructor Create(aOwner: TComponent); override; constructor Create(aOwner: TComponent); override;
// //
property fileName: string read fFilename write fFilename; property fileName: string read fFilename write fFilename;
property modified: boolean read fModified write fModified; property modified: boolean read fModified write fModified;
property project: TCEProject read fAssocProject write fAssocProject; property project: TCEProject read fAssocProject write fAssocProject;
//
property isDSource: boolean read getIfDSource;
property isProjectSource: boolean read getIfConfig;
end; end;
var var
@ -29,7 +34,7 @@ var
implementation implementation
uses uses
graphics; graphics, ce_main;
constructor TCESynMemo.Create(aOwner: TComponent); constructor TCESynMemo.Create(aOwner: TComponent);
begin begin
@ -52,6 +57,16 @@ begin
Highlighter := D2Syn; Highlighter := D2Syn;
end; end;
function TCESynMemo.getIfDSource: Boolean;
begin
exit(Highlighter = D2Syn);
end;
function TCESynMemo.getIfConfig: Boolean;
begin
exit(Highlighter = mainForm.LfmSyn);
end;
initialization initialization
D2Syn := TSynD2Syn.create(nil); D2Syn := TSynD2Syn.create(nil);
finalization finalization

View File

@ -100,9 +100,6 @@ type
implementation implementation
{$R *.lfm} {$R *.lfm}
uses
ce_main;
(******************************************************************************* (*******************************************************************************
* TCEWidget * TCEWidget
*) *)
@ -119,8 +116,8 @@ begin
fUpdaterAuto.OnTimer := @updaterAutoProc; fUpdaterAuto.OnTimer := @updaterAutoProc;
fUpdaterDelay := TTimer.Create(self); fUpdaterDelay := TTimer.Create(self);
updaterByLoopInterval := 50; updaterByLoopInterval := 70;
updaterByDelayDuration := 1000; updaterByDelayDuration := 1250;
DockMaster.MakeDockable(Self, true, true, true); DockMaster.MakeDockable(Self, true, true, true);
DockMaster.GetAnchorSite(Self).Header.HeaderPosition := adlhpTop; DockMaster.GetAnchorSite(Self).Header.HeaderPosition := adlhpTop;