1 (* Copyright (C) Doom 2D: Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *)
16 {$INCLUDE a_modes.inc}
19 interface
21 uses
27 // ////////////////////////////////////////////////////////////////////////// //
28 type
30 public
36 public
39 public
44 // ////////////////////////////////////////////////////////////////////////// //
45 type
47 private
53 public
62 // ////////////////////////////////////////////////////////////////////////// //
63 type
65 public
71 // ////////////////////////////////////////////////////////////////////////// //
72 type
74 public
84 public
87 public
92 class procedure parseErrorFmt (pr: TTextParser; const afmt: AnsiString; const args: array of const);
94 class function parse (clist: TExprConstList; pr: TTextParser; allowAssign: Boolean=false): TExprBase;
95 class function parse (clist: TExprConstList; const str: AnsiString; allowAssign: Boolean=false): TExprBase;
103 public
110 private
112 public
122 private
124 public
133 private
135 public
147 private
149 public
156 public
162 public
168 private
171 public
180 private
182 private
184 public
190 TBinExprAdd = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
191 TBinExprSub = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
192 TBinExprMul = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
193 TBinExprDiv = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
194 TBinExprMod = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
196 TBinExprLogAnd = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
197 TBinExprLogOr = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
199 TBinExprCmpLess = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
200 TBinExprCmpGreat = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
201 TBinExprCmpLessEqu = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
202 TBinExprCmpGreatEqu = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
203 TBinExprCmpEqu = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
204 TBinExprCmpNotEqu = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
206 TBinAssign = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
209 private
211 public
220 // ////////////////////////////////////////////////////////////////////////// //
224 implementation
226 uses
227 utils;
230 // ////////////////////////////////////////////////////////////////////////// //
232 begin
237 begin
242 // ////////////////////////////////////////////////////////////////////////// //
244 begin
245 if (pr <> nil) then begin tokLine := pr.tokLine; tokCol := pr.tokCol; end else begin tokLine := 0; tokCol := 0; end;
249 constructor TExomaParseException.CreateFmt (pr: TTextParser; const afmt: AnsiString; const args: array of const);
250 begin
251 if (pr <> nil) then begin tokLine := pr.tokLine; tokCol := pr.tokCol; end else begin tokLine := 0; tokCol := 0; end;
256 // ////////////////////////////////////////////////////////////////////////// //
258 begin
295 // ////////////////////////////////////////////////////////////////////////// //
296 (*
297 procedure dumpPublishedProperties (obj: TObject);
298 var
299 pt: PTypeData;
300 pi: PTypeInfo;
301 i, j: Integer;
302 pp: PPropList;
303 begin
304 if (obj = nil) then exit;
305 //e_LogWritefln('Object of type ''%s'':', [obj.ClassName]);
306 pi := obj.ClassInfo;
307 pt := GetTypeData(pi);
308 //e_LogWritefln('property count: %s', [pt.PropCount]);
309 GetMem(pp, pt^.PropCount*sizeof(Pointer));
310 try
311 j := GetPropList(pi, [tkInteger, tkBool, tkSString, tkLString, tkAString, tkSet, tkEnumeration], pp);
312 //e_LogWritefln('ordinal property count: %s', [j]);
313 for i := 0 to j-1 do
314 begin
315 {
316 if (typinfo.PropType(obj, pp^[i].name) in [tkSString, tkLString, tkAString]) then
317 begin
318 e_LogWritefln(' #%s: <%s>; type: %s; value: <%s>', [i+1, pp^[i].name, typeKind2Str(typinfo.PropType(obj, pp^[i].name)), GetStrProp(obj, pp^[i])]);
319 end
320 else if (typinfo.PropType(obj, pp^[i].name) = tkSet) then
321 begin
322 e_LogWritefln(' #%s: <%s>; type: %s; value: %s', [i+1, pp^[i].name, typeKind2Str(typinfo.PropType(obj, pp^[i].name)), GetSetProp(obj, pp^[i], true)]);
323 end
324 else if (typinfo.PropType(obj, pp^[i].name) = tkEnumeration) then
325 begin
326 e_LogWritefln(' #%s: <%s>; type: %s; value: <%s>', [i+1, pp^[i].name, typeKind2Str(typinfo.PropType(obj, pp^[i].name)), GetEnumProp(obj, pp^[i])]);
327 end
328 else
329 begin
330 e_LogWritefln(' #%s: <%s>; type: %s; value: %s', [i+1, pp^[i].name, typeKind2Str(typinfo.PropType(obj, pp^[i].name)), GetOrdProp(obj, pp^[i])]);
331 end;
332 }
333 end;
334 finally
335 FreeMem(pp);
336 end;
337 end;
338 *)
341 // ////////////////////////////////////////////////////////////////////////// //
343 var
348 begin
354 pc := GetPropList(pi, [tkInteger, tkBool, tkSString, tkLString, tkAString, {tkSet,} tkEnumeration], pl);
356 begin
358 begin
364 end
365 else
366 begin
373 begin
383 var
385 begin
388 begin
395 //tkFloat: result := 'Float';
396 //tkClass: result := 'Class';
397 //tkInt64: result := 'Int64';
398 //tkClassRef: result := 'ClassRef';
407 var
409 begin
412 begin
417 tkBool: if TExprBase.coerce2bool(v) then SetOrdProp(obj, pl^[idx], 1) else SetOrdProp(obj, pl^[idx], 0);
419 //tkFloat: result := 'Float';
420 //tkClass: result := 'Class';
421 //tkInt64: result := 'Int64';
422 //tkClassRef: result := 'ClassRef';
430 // ////////////////////////////////////////////////////////////////////////// //
431 class procedure TExprScope.error (const amsg: AnsiString); begin raise TExomaException.Create(amsg); end;
432 class procedure TExprScope.errorfmt (const afmt: AnsiString; const args: array of const); begin raise TExomaException.CreateFmt(afmt, args); end;
434 function TExprScope.getObj (const aname: AnsiString): TObject; begin result := nil; errorfmt('unknown object ''%s''', [aname]); end;
435 function TExprScope.getField (obj: TObject; const afldname: AnsiString): Variant; begin result := Unassigned; errorfmt('unknown field ''%s''', [afldname]); end;
436 procedure TExprScope.setField (obj: TObject; const afldname: AnsiString; var aval: Variant); begin errorfmt('unknown field ''%s''', [afldname]); end;
439 // ////////////////////////////////////////////////////////////////////////// //
440 class procedure TExprBase.error (const amsg: AnsiString); begin raise TExomaException.Create(amsg); end;
441 class procedure TExprBase.errorfmt (const afmt: AnsiString; const args: array of const); begin raise TExomaException.CreateFmt(afmt, args); end;
443 class procedure TExprBase.parseError (pr: TTextParser; const amsg: AnsiString); begin raise TExomaParseException.Create(pr, amsg); end;
444 class procedure TExprBase.parseErrorFmt (pr: TTextParser; const afmt: AnsiString; const args: array of const); begin raise TExomaParseException.CreateFmt(pr, afmt, args); end;
447 begin
455 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := (LongInt(v0) <> 0);
463 begin
471 begin
479 begin
484 begin
489 begin
500 procedure TExprBase.assign (scope: TExprScope; var v: Variant); begin error('not an lvalue'); end;
503 // ////////////////////////////////////////////////////////////////////////// //
505 destructor TExprStatList.Destroy (); var f: Integer; begin for f := 0 to High(mList) do mList[f].Free(); mList := nil; end;
508 begin
510 begin
517 var
519 begin
524 var
526 begin
531 var
534 begin
538 try
540 except
547 // ////////////////////////////////////////////////////////////////////////// //
552 begin
557 function TExprCond.toString (): AnsiString; begin result := '('+mCond.toString()+'?'+mTrue.toString()+':'+mFalse.toString()+')'; end;
560 begin
568 // ////////////////////////////////////////////////////////////////////////// //
570 function TObjExpr.value (scope: TExprScope): Variant; begin result := UInt64(PtrUInt(Pointer(scope.getObj(mName)))); end;
575 // ////////////////////////////////////////////////////////////////////////// //
581 function TLitExpr.toString (): AnsiString; begin result := VarToStr(mValue); if isStr(mValue) then result := quoteStr(result); end;
582 function TLitExpr.clone (): TExprBase; begin result := TLitExpr.Create(0); (result as TLitExpr).mValue := mValue; end;
585 // ////////////////////////////////////////////////////////////////////////// //
588 function TUnExpr.clone (): TExprBase; begin result := (self.ClassType.Create() as TUnExpr); (result as TUnExpr).mOp0 := mOp0.clone(); end;
591 begin
606 begin
614 // ////////////////////////////////////////////////////////////////////////// //
616 begin
622 begin
624 if (varType(result) <> varQWord) then errorfmt('can''t take field ''%s'' value of non-object', [mField]);
629 var
631 begin
633 if (varType(o) <> varQWord) then errorfmt('can''t assign value to field ''%s'' of non-object', [mField]);
642 // ////////////////////////////////////////////////////////////////////////// //
645 function TBinExpr.clone (): TExprBase; begin result := (self.ClassType.Create() as TBinExpr); (result as TBinExpr).mOp0 := mOp0.clone(); (result as TBinExpr).mOp1 := mOp1.clone(); end;
648 begin
650 begin
652 begin
663 end
665 begin
672 end
674 begin
683 end
684 else
685 begin
692 // ////////////////////////////////////////////////////////////////////////// //
694 var
696 begin
703 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := LongInt(result)+LongInt(r1);
708 function TBinExprAdd.toString (): AnsiString; begin result := '('+mOp0.toString()+'+'+mOp1.toString+')'; end;
711 var
713 begin
719 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := LongInt(result)-LongInt(r1);
724 function TBinExprSub.toString (): AnsiString; begin result := '('+mOp0.toString()+'-'+mOp1.toString+')'; end;
727 var
729 begin
735 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := LongInt(result)*LongInt(r1);
740 function TBinExprMul.toString (): AnsiString; begin result := '('+mOp0.toString()+'*'+mOp1.toString+')'; end;
743 var
745 begin
751 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := LongInt(result) div LongInt(r1);
756 function TBinExprDiv.toString (): AnsiString; begin result := '('+mOp0.toString()+'/'+mOp1.toString+')'; end;
759 var
761 begin
766 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := LongInt(result) mod LongInt(r1);
771 function TBinExprMod.toString (): AnsiString; begin result := '('+mOp0.toString()+'%'+mOp1.toString+')'; end;
774 begin
780 function TBinExprLogAnd.toString (): AnsiString; begin result := '('+mOp0.toString()+'&&'+mOp1.toString+')'; end;
783 begin
789 function TBinExprLogOr.toString (): AnsiString; begin result := '('+mOp0.toString()+'||'+mOp1.toString+')'; end;
792 var
794 begin
800 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := Boolean(LongInt(result) < LongInt(r1));
806 function TBinExprCmpLess.toString (): AnsiString; begin result := '('+mOp0.toString()+'<'+mOp1.toString+')'; end;
809 var
811 begin
817 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := Boolean(LongInt(result) > LongInt(r1));
823 function TBinExprCmpGreat.toString (): AnsiString; begin result := '('+mOp0.toString()+'>'+mOp1.toString+')'; end;
826 var
828 begin
834 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := Boolean(LongInt(result) <= LongInt(r1));
840 function TBinExprCmpLessEqu.toString (): AnsiString; begin result := '('+mOp0.toString()+'<='+mOp1.toString+')'; end;
843 var
845 begin
851 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := Boolean(LongInt(result) >= LongInt(r1));
857 function TBinExprCmpGreatEqu.toString (): AnsiString; begin result := '('+mOp0.toString()+'>='+mOp1.toString+')'; end;
860 var
862 begin
868 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := Boolean(LongInt(result) = LongInt(r1));
876 function TBinExprCmpEqu.toString (): AnsiString; begin result := '('+mOp0.toString()+'=='+mOp1.toString+')'; end;
879 var
881 begin
887 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := Boolean(LongInt(result) <> LongInt(r1));
895 function TBinExprCmpNotEqu.toString (): AnsiString; begin result := '('+mOp0.toString()+'<>'+mOp1.toString+')'; end;
898 // ////////////////////////////////////////////////////////////////////////// //
900 begin
905 function TBinAssign.toString (): AnsiString; begin result := mOp0.toString()+'='+mOp1.toString(); end;
908 // ////////////////////////////////////////////////////////////////////////// //
909 class function TExprBase.parse (clist: TExprConstList; const str: AnsiString; allowAssign: Boolean=false): TExprBase;
910 var
912 begin
914 try
916 if (pr.tokType <> pr.TTEOF) then begin result.Free(); parseError(pr, 'extra code in expression'); end;
917 finally
922 class function TExprBase.parseStatList (clist: TExprConstList; const str: AnsiString): TExprBase;
923 var
927 begin
932 try
933 try
935 begin
940 //writeln(': ', e.toString());
943 //writeln('tt=', pr.tokType, ' <', pr.tokStr, '>');
944 //writeln(r.toString());
949 except
954 else
957 finally
964 class function TExprBase.parse (clist: TExprConstList; pr: TTextParser; allowAssign: Boolean=false): TExprBase;
969 var
972 begin
974 try
976 if pr.eatDelim('!') then begin result := doTerm(); result := TUnExprNot.Create(result); exit; end;
978 if pr.eatDelim('-') then begin result := doTerm(); result := TUnExprNeg.Create(result); exit; end;
982 begin
984 if (pr.tokStr = 'false') then begin result := TLitExpr.Create(false); pr.skipToken(); exit; end;
985 if (CompareText(pr.tokStr, 'true') = 0) or (CompareText(pr.tokStr, 'false') = 0) then parseError(pr, '`true` and `false` are case-sensitive');
988 begin
990 begin
992 exit;
998 begin
1002 exit;
1004 except
1012 begin
1014 try
1016 begin
1022 except
1029 begin
1031 try
1033 begin
1038 except
1045 begin
1047 try
1049 begin
1053 else if pr.eatTT(pr.TTGreatEqu) then result := TBinExprCmpGreatEqu.Create(result, doPlusMinus())
1056 except
1063 begin
1065 try
1067 begin
1072 except
1079 begin
1081 try
1083 begin
1086 except
1093 begin
1095 try
1097 begin
1100 except
1106 // funcall, [], dot
1107 // !, ~
1108 // *, /, %
1109 // +, -
1110 // <<, >>
1111 // <, <=, >, >=
1112 // ==, !=
1113 // &
1114 // ^
1115 // |
1116 // &&
1117 // ||
1120 var
1124 begin
1126 try
1128 begin
1136 begin
1138 break;
1140 //assert(false);
1142 begin
1149 except
1156 var
1158 begin
1160 // ternary
1162 begin
1165 try
1170 except
1176 var
1178 begin
1181 try
1183 try
1185 finally
1188 except
1193 else
1199 {
1200 varEmpty:
1201 varNull:
1202 varSingle:
1203 varDouble:
1204 varDecimal:
1205 varCurrency:
1206 varDate:
1207 varOleStr:
1208 varStrArg:
1209 varString:
1210 varDispatch:
1211 varBoolean:
1212 varVariant:
1213 varUnknown:
1214 varShortInt:
1215 varSmallint:
1216 varInteger:
1217 varInt64:
1218 varByte:
1219 varWord:
1220 varLongWord:
1221 varQWord:
1222 varError:
1223 }