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, version 3 of the License ONLY.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *)
15 {$INCLUDE a_modes.inc}
18 interface
20 uses
26 // ////////////////////////////////////////////////////////////////////////// //
27 type
29 public
35 public
38 public
43 // ////////////////////////////////////////////////////////////////////////// //
44 type
46 private
52 public
61 // ////////////////////////////////////////////////////////////////////////// //
62 type
64 public
70 // ////////////////////////////////////////////////////////////////////////// //
71 type
73 public
83 public
86 public
91 class procedure parseErrorFmt (pr: TTextParser; const afmt: AnsiString; const args: array of const);
93 class function parse (clist: TExprConstList; pr: TTextParser; allowAssign: Boolean=false): TExprBase;
94 class function parse (clist: TExprConstList; const str: AnsiString; allowAssign: Boolean=false): TExprBase;
102 public
109 private
111 public
121 private
123 public
132 private
134 public
146 private
148 public
155 public
161 public
167 private
170 public
179 private
181 private
183 public
189 TBinExprAdd = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
190 TBinExprSub = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
191 TBinExprMul = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
192 TBinExprDiv = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
193 TBinExprMod = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
195 TBinExprLogAnd = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
196 TBinExprLogOr = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
198 TBinExprCmpLess = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
199 TBinExprCmpGreat = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
200 TBinExprCmpLessEqu = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
201 TBinExprCmpGreatEqu = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
202 TBinExprCmpEqu = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
203 TBinExprCmpNotEqu = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
205 TBinAssign = class(TBinExpr) public function value (scope: TExprScope): Variant; override; function toString (): AnsiString; override; end;
208 private
210 public
219 // ////////////////////////////////////////////////////////////////////////// //
223 implementation
225 uses
226 utils;
229 // ////////////////////////////////////////////////////////////////////////// //
231 begin
236 begin
241 // ////////////////////////////////////////////////////////////////////////// //
243 begin
244 if (pr <> nil) then begin tokLine := pr.tokLine; tokCol := pr.tokCol; end else begin tokLine := 0; tokCol := 0; end;
248 constructor TExomaParseException.CreateFmt (pr: TTextParser; const afmt: AnsiString; const args: array of const);
249 begin
250 if (pr <> nil) then begin tokLine := pr.tokLine; tokCol := pr.tokCol; end else begin tokLine := 0; tokCol := 0; end;
255 // ////////////////////////////////////////////////////////////////////////// //
257 begin
294 // ////////////////////////////////////////////////////////////////////////// //
295 (*
296 procedure dumpPublishedProperties (obj: TObject);
297 var
298 pt: PTypeData;
299 pi: PTypeInfo;
300 i, j: Integer;
301 pp: PPropList;
302 begin
303 if (obj = nil) then exit;
304 //e_LogWritefln('Object of type ''%s'':', [obj.ClassName]);
305 pi := obj.ClassInfo;
306 pt := GetTypeData(pi);
307 //e_LogWritefln('property count: %s', [pt.PropCount]);
308 GetMem(pp, pt^.PropCount*sizeof(Pointer));
309 try
310 j := GetPropList(pi, [tkInteger, tkBool, tkSString, tkLString, tkAString, tkSet, tkEnumeration], pp);
311 //e_LogWritefln('ordinal property count: %s', [j]);
312 for i := 0 to j-1 do
313 begin
314 {
315 if (typinfo.PropType(obj, pp^[i].name) in [tkSString, tkLString, tkAString]) then
316 begin
317 e_LogWritefln(' #%s: <%s>; type: %s; value: <%s>', [i+1, pp^[i].name, typeKind2Str(typinfo.PropType(obj, pp^[i].name)), GetStrProp(obj, pp^[i])]);
318 end
319 else if (typinfo.PropType(obj, pp^[i].name) = tkSet) then
320 begin
321 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)]);
322 end
323 else if (typinfo.PropType(obj, pp^[i].name) = tkEnumeration) then
324 begin
325 e_LogWritefln(' #%s: <%s>; type: %s; value: <%s>', [i+1, pp^[i].name, typeKind2Str(typinfo.PropType(obj, pp^[i].name)), GetEnumProp(obj, pp^[i])]);
326 end
327 else
328 begin
329 e_LogWritefln(' #%s: <%s>; type: %s; value: %s', [i+1, pp^[i].name, typeKind2Str(typinfo.PropType(obj, pp^[i].name)), GetOrdProp(obj, pp^[i])]);
330 end;
331 }
332 end;
333 finally
334 FreeMem(pp);
335 end;
336 end;
337 *)
340 // ////////////////////////////////////////////////////////////////////////// //
342 var
347 begin
353 pc := GetPropList(pi, [tkInteger, tkBool, tkSString, tkLString, tkAString, {tkSet,} tkEnumeration], pl);
355 begin
357 begin
363 end
364 else
365 begin
372 begin
382 var
384 begin
387 begin
394 //tkFloat: result := 'Float';
395 //tkClass: result := 'Class';
396 //tkInt64: result := 'Int64';
397 //tkClassRef: result := 'ClassRef';
406 var
408 begin
411 begin
416 tkBool: if TExprBase.coerce2bool(v) then SetOrdProp(obj, pl^[idx], 1) else SetOrdProp(obj, pl^[idx], 0);
418 //tkFloat: result := 'Float';
419 //tkClass: result := 'Class';
420 //tkInt64: result := 'Int64';
421 //tkClassRef: result := 'ClassRef';
429 // ////////////////////////////////////////////////////////////////////////// //
430 class procedure TExprScope.error (const amsg: AnsiString); begin raise TExomaException.Create(amsg); end;
431 class procedure TExprScope.errorfmt (const afmt: AnsiString; const args: array of const); begin raise TExomaException.CreateFmt(afmt, args); end;
433 function TExprScope.getObj (const aname: AnsiString): TObject; begin result := nil; errorfmt('unknown object ''%s''', [aname]); end;
434 function TExprScope.getField (obj: TObject; const afldname: AnsiString): Variant; begin result := Unassigned; errorfmt('unknown field ''%s''', [afldname]); end;
435 procedure TExprScope.setField (obj: TObject; const afldname: AnsiString; var aval: Variant); begin errorfmt('unknown field ''%s''', [afldname]); end;
438 // ////////////////////////////////////////////////////////////////////////// //
439 class procedure TExprBase.error (const amsg: AnsiString); begin raise TExomaException.Create(amsg); end;
440 class procedure TExprBase.errorfmt (const afmt: AnsiString; const args: array of const); begin raise TExomaException.CreateFmt(afmt, args); end;
442 class procedure TExprBase.parseError (pr: TTextParser; const amsg: AnsiString); begin raise TExomaParseException.Create(pr, amsg); end;
443 class procedure TExprBase.parseErrorFmt (pr: TTextParser; const afmt: AnsiString; const args: array of const); begin raise TExomaParseException.CreateFmt(pr, afmt, args); end;
446 begin
454 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := (LongInt(v0) <> 0);
462 begin
470 begin
478 begin
483 begin
488 begin
499 procedure TExprBase.assign (scope: TExprScope; var v: Variant); begin error('not an lvalue'); end;
502 // ////////////////////////////////////////////////////////////////////////// //
504 destructor TExprStatList.Destroy (); var f: Integer; begin for f := 0 to High(mList) do mList[f].Free(); mList := nil; end;
507 begin
509 begin
516 var
518 begin
523 var
525 begin
530 var
533 begin
537 try
539 except
546 // ////////////////////////////////////////////////////////////////////////// //
551 begin
556 function TExprCond.toString (): AnsiString; begin result := '('+mCond.toString()+'?'+mTrue.toString()+':'+mFalse.toString()+')'; end;
559 begin
567 // ////////////////////////////////////////////////////////////////////////// //
569 function TObjExpr.value (scope: TExprScope): Variant; begin result := UInt64(PtrUInt(Pointer(scope.getObj(mName)))); end;
574 // ////////////////////////////////////////////////////////////////////////// //
580 function TLitExpr.toString (): AnsiString; begin result := VarToStr(mValue); if isStr(mValue) then result := quoteStr(result); end;
581 function TLitExpr.clone (): TExprBase; begin result := TLitExpr.Create(0); (result as TLitExpr).mValue := mValue; end;
584 // ////////////////////////////////////////////////////////////////////////// //
587 function TUnExpr.clone (): TExprBase; begin result := (self.ClassType.Create() as TUnExpr); (result as TUnExpr).mOp0 := mOp0.clone(); end;
590 begin
605 begin
613 // ////////////////////////////////////////////////////////////////////////// //
615 begin
621 begin
623 if (varType(result) <> varQWord) then errorfmt('can''t take field ''%s'' value of non-object', [mField]);
628 var
630 begin
632 if (varType(o) <> varQWord) then errorfmt('can''t assign value to field ''%s'' of non-object', [mField]);
641 // ////////////////////////////////////////////////////////////////////////// //
644 function TBinExpr.clone (): TExprBase; begin result := (self.ClassType.Create() as TBinExpr); (result as TBinExpr).mOp0 := mOp0.clone(); (result as TBinExpr).mOp1 := mOp1.clone(); end;
647 begin
649 begin
651 begin
662 end
664 begin
671 end
673 begin
682 end
683 else
684 begin
691 // ////////////////////////////////////////////////////////////////////////// //
693 var
695 begin
702 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := LongInt(result)+LongInt(r1);
707 function TBinExprAdd.toString (): AnsiString; begin result := '('+mOp0.toString()+'+'+mOp1.toString+')'; end;
710 var
712 begin
718 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := LongInt(result)-LongInt(r1);
723 function TBinExprSub.toString (): AnsiString; begin result := '('+mOp0.toString()+'-'+mOp1.toString+')'; end;
726 var
728 begin
734 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := LongInt(result)*LongInt(r1);
739 function TBinExprMul.toString (): AnsiString; begin result := '('+mOp0.toString()+'*'+mOp1.toString+')'; end;
742 var
744 begin
750 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := LongInt(result) div LongInt(r1);
755 function TBinExprDiv.toString (): AnsiString; begin result := '('+mOp0.toString()+'/'+mOp1.toString+')'; end;
758 var
760 begin
765 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := LongInt(result) mod LongInt(r1);
770 function TBinExprMod.toString (): AnsiString; begin result := '('+mOp0.toString()+'%'+mOp1.toString+')'; end;
773 begin
779 function TBinExprLogAnd.toString (): AnsiString; begin result := '('+mOp0.toString()+'&&'+mOp1.toString+')'; end;
782 begin
788 function TBinExprLogOr.toString (): AnsiString; begin result := '('+mOp0.toString()+'||'+mOp1.toString+')'; end;
791 var
793 begin
799 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := Boolean(LongInt(result) < LongInt(r1));
805 function TBinExprCmpLess.toString (): AnsiString; begin result := '('+mOp0.toString()+'<'+mOp1.toString+')'; end;
808 var
810 begin
816 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := Boolean(LongInt(result) > LongInt(r1));
822 function TBinExprCmpGreat.toString (): AnsiString; begin result := '('+mOp0.toString()+'>'+mOp1.toString+')'; end;
825 var
827 begin
833 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := Boolean(LongInt(result) <= LongInt(r1));
839 function TBinExprCmpLessEqu.toString (): AnsiString; begin result := '('+mOp0.toString()+'<='+mOp1.toString+')'; end;
842 var
844 begin
850 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := Boolean(LongInt(result) >= LongInt(r1));
856 function TBinExprCmpGreatEqu.toString (): AnsiString; begin result := '('+mOp0.toString()+'>='+mOp1.toString+')'; end;
859 var
861 begin
867 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := Boolean(LongInt(result) = LongInt(r1));
875 function TBinExprCmpEqu.toString (): AnsiString; begin result := '('+mOp0.toString()+'=='+mOp1.toString+')'; end;
878 var
880 begin
886 varShortInt, varSmallint, varInteger, varByte, varWord, varLongWord: result := Boolean(LongInt(result) <> LongInt(r1));
894 function TBinExprCmpNotEqu.toString (): AnsiString; begin result := '('+mOp0.toString()+'<>'+mOp1.toString+')'; end;
897 // ////////////////////////////////////////////////////////////////////////// //
899 begin
904 function TBinAssign.toString (): AnsiString; begin result := mOp0.toString()+'='+mOp1.toString(); end;
907 // ////////////////////////////////////////////////////////////////////////// //
908 class function TExprBase.parse (clist: TExprConstList; const str: AnsiString; allowAssign: Boolean=false): TExprBase;
909 var
911 begin
913 try
915 if (pr.tokType <> pr.TTEOF) then begin result.Free(); parseError(pr, 'extra code in expression'); end;
916 finally
921 class function TExprBase.parseStatList (clist: TExprConstList; const str: AnsiString): TExprBase;
922 var
926 begin
931 try
932 try
934 begin
939 //writeln(': ', e.toString());
942 //writeln('tt=', pr.tokType, ' <', pr.tokStr, '>');
943 //writeln(r.toString());
948 except
953 else
956 finally
963 class function TExprBase.parse (clist: TExprConstList; pr: TTextParser; allowAssign: Boolean=false): TExprBase;
968 var
971 begin
973 try
975 if pr.eatDelim('!') then begin result := doTerm(); result := TUnExprNot.Create(result); exit; end;
977 if pr.eatDelim('-') then begin result := doTerm(); result := TUnExprNeg.Create(result); exit; end;
981 begin
983 if (pr.tokStr = 'false') then begin result := TLitExpr.Create(false); pr.skipToken(); exit; end;
984 if (CompareText(pr.tokStr, 'true') = 0) or (CompareText(pr.tokStr, 'false') = 0) then parseError(pr, '`true` and `false` are case-sensitive');
987 begin
989 begin
991 exit;
997 begin
1001 exit;
1003 except
1011 begin
1013 try
1015 begin
1021 except
1028 begin
1030 try
1032 begin
1037 except
1044 begin
1046 try
1048 begin
1052 else if pr.eatTT(pr.TTGreatEqu) then result := TBinExprCmpGreatEqu.Create(result, doPlusMinus())
1055 except
1062 begin
1064 try
1066 begin
1071 except
1078 begin
1080 try
1082 begin
1085 except
1092 begin
1094 try
1096 begin
1099 except
1105 // funcall, [], dot
1106 // !, ~
1107 // *, /, %
1108 // +, -
1109 // <<, >>
1110 // <, <=, >, >=
1111 // ==, !=
1112 // &
1113 // ^
1114 // |
1115 // &&
1116 // ||
1119 var
1123 begin
1125 try
1127 begin
1135 begin
1137 break;
1139 //assert(false);
1141 begin
1148 except
1155 var
1157 begin
1159 // ternary
1161 begin
1164 try
1169 except
1175 var
1177 begin
1180 try
1182 try
1184 finally
1187 except
1192 else
1198 {
1199 varEmpty:
1200 varNull:
1201 varSingle:
1202 varDouble:
1203 varDecimal:
1204 varCurrency:
1205 varDate:
1206 varOleStr:
1207 varStrArg:
1208 varString:
1209 varDispatch:
1210 varBoolean:
1211 varVariant:
1212 varUnknown:
1213 varShortInt:
1214 varSmallint:
1215 varInteger:
1216 varInt64:
1217 varByte:
1218 varWord:
1219 varLongWord:
1220 varQWord:
1221 varError:
1222 }