@@ -109,7 +109,7 @@ TPascalParser = class(TObject)
109109 // -- routines ----------------------------------------------------------
110110 function ParseRoutine (IsFunction: Boolean; IsConstructor: Boolean = False;
111111 ForceForward: Boolean = False;
112- ClsName: string = ' ' ): XTree_Function ;
112+ ClsName: string = ' ' ): XTree_Node ;
113113
114114 // -- statements --------------------------------------------------------
115115 function ParseBlock (): XTree_ExprList;
@@ -164,12 +164,32 @@ function ParsePascal(Tokenizer: TTokenizer; ctx: TCompilerContext = nil): XTree_
164164 ctx.AddType(' longword' , ctx.GetType(xtUInt32));
165165 ctx.AddType(' word' , ctx.GetType(xtUInt32));
166166 ctx.AddType(' byte' , ctx.GetType(xtUInt8));
167+ ctx.AddType(' boolean' , ctx.GetType(xtBool));
167168
168169 Parser := TPascalParser.Create(Tokenizer, ctx);
169170 Result := Parser.ParseProgram();
170171 Parser.Free();
171172end ;
172173
174+
175+ function CompoundToBinaryOp (CompOp: EOperator): EOperator;
176+ begin
177+ case CompOp of
178+ op_AsgnADD: Result := op_Add;
179+ op_AsgnSUB: Result := op_Sub;
180+ op_AsgnMUL: Result := op_Mul;
181+ op_AsgnDIV: Result := op_Div;
182+ op_AsgnMOD: Result := op_Mod;
183+ op_AsgnBND: Result := op_BND;
184+ op_AsgnBOR: Result := op_BOR;
185+ op_AsgnXOR: Result := op_XOR;
186+ op_AsgnSHL: Result := op_SHL;
187+ op_AsgnSHR: Result := op_SHR;
188+ else
189+ Result := op_Unknown;
190+ end ;
191+ end ;
192+
173193// -----------------------------------------------------------------------------
174194// Constructor / basic navigation
175195// -----------------------------------------------------------------------------
@@ -253,8 +273,10 @@ function TPascalParser.GetPascalPrecedence(Token: ETokenKind): Int8;
253273 tkPLUS, tkMINUS,
254274 tkOR, tkXOR: Result := 4 ;
255275 tkEQ, tkNE, tkLT, tkLTE,
256- tkGT, tkGTE, tkIN, tkKW_IS: Result := 3 ;
276+ tkGT, tkGTE, tkIN, tkKW_IS: Result := 3 ;
257277 tkASGN: Result := 2 ;
278+ tkPLUS_ASGN, tkMINUS_ASGN, tkMUL_ASGN, tkDIV_ASGN:
279+ Result := 2 ;
258280 else
259281 Result := -1 ;
260282 end ;
@@ -548,7 +570,7 @@ function TPascalParser.ParseProgram(): XTree_Node;
548570
549571function TPascalParser.ParseDeclarations (): XNodeArray;
550572var
551- FuncNode: XTree_Function ;
573+ FuncNode: XTree_Node ;
552574 S: string;
553575begin
554576 Result := nil ;
@@ -701,6 +723,11 @@ function TPascalParser.ParseTypeDefinition(): XType;
701723 TypeName, MangledName: string;
702724 ExplicitTypes: XTypeArray;
703725 i: Int32;
726+ IsFunc, IsRef: Boolean;
727+ ArgTypes: XTypeArray;
728+ ArgPass: TPassArgsBy;
729+ RetType, PType: XType;
730+ Idents: TStringArray;
704731begin
705732 if Current.Token = tkKW_RECORD then
706733 begin
@@ -731,6 +758,69 @@ function TPascalParser.ParseTypeDefinition(): XType;
731758 begin
732759 FContext.RaiseException(' Specialize var not yet implemented' , DocPos);
733760 end
761+ else if (Current.Token = tkKW_FUNC) or
762+ ((Current.Token = tkIDENT) and
763+ ((XprCase(Current.Value ) = ' function' ) or (XprCase(Current.Value ) = ' procedure' ))) then
764+ begin
765+ // Inline function pointer type: function(a, b: Int32): String;
766+ IsFunc := (Current.Token = tkKW_FUNC) or (XprCase(Current.Value ) = ' function' );
767+ Next(); // consume 'function' or 'procedure'
768+
769+ SetLength(ArgTypes, 0 );
770+ SetLength(ArgPass, 0 );
771+ RetType := nil ;
772+
773+ if NextIf(tkLPARENTHESES) then
774+ begin
775+ while Current.Token <> tkRPARENTHESES do
776+ begin
777+ IsRef := NextIf(tkKW_VAR) or NextIf(tkKW_REF) or NextIfIdent(' out' );
778+ if NextIfIdent(' const' ) then IsRef := False;
779+
780+ // Differentiate between named args "n: Int32" and unnamed args "Int32"
781+ if (Current.Token = tkIDENT) and (Peek(1 ).Token in [tkCOMMA, tkCOLON]) then
782+ begin
783+ SetLength(Idents, 0 );
784+ repeat
785+ Idents += Current.Value ;
786+ Consume(tkIDENT);
787+ until not NextIf(tkCOMMA);
788+
789+ Consume(tkCOLON);
790+ PType := ParseTypeDefinition();
791+
792+ for i := 0 to High(Idents) do
793+ begin
794+ ArgTypes += PType;
795+ if IsRef then ArgPass += pbRef else ArgPass += pbCopy;
796+ end ;
797+ end
798+ else
799+ begin
800+ PType := ParseTypeDefinition();
801+ ArgTypes += PType;
802+ if IsRef then ArgPass += pbRef else ArgPass += pbCopy;
803+ end ;
804+
805+ // Arguments can be separated by ';' or ',' in function signatures
806+ if not (NextIf(tkSEMI) or NextIf(tkCOMMA)) then Break;
807+ end ;
808+ Consume(tkRPARENTHESES);
809+ end ;
810+
811+ if IsFunc then
812+ begin
813+ Consume(tkCOLON);
814+ RetType := ParseTypeDefinition();
815+ end ;
816+
817+ // Silently skip common Pascal modifiers: 'of object' or 'is nested'
818+ if NextIfIdent(' of' ) then Consume(tkIDENT);
819+ if NextIfIdent(' is' ) then Consume(tkIDENT);
820+
821+ Result := XType_Method.Create(' ' , ArgTypes, ArgPass, RetType, False);
822+ FContext.AddManagedType(Result);
823+ end
734824 else if Current.Token = tkIDENT then
735825 begin
736826 // Handle qualified names (System.Integer etc.) – just take the last part
@@ -775,7 +865,7 @@ function TPascalParser.ParseEnum(const TypeName: string): XNodeArray;
775865 Doc: TDocPos;
776866 ET: XType_Enum;
777867begin
778- SetLength( Result, 0 ) ;
868+ Result := nil ;
779869 Doc := DocPos;
780870 Consume(tkLPARENTHESES);
781871 EnumIdx := 0 ;
@@ -881,7 +971,7 @@ function TPascalParser.ParseClassDecl(const ClsName, GenericParams: string): XTr
881971var
882972 Param, ParentName: string;
883973 Fields, TypeDecls, Methods: XNodeArray;
884- FuncNode: XTree_Function ;
974+ FuncNode: XTree_Node ;
885975 IdentList: XIdentNodeList;
886976 FieldType: XType;
887977 Doc: TDocPos;
@@ -1129,7 +1219,7 @@ function TPascalParser.ParseVarBlock(IsConst: Boolean): XNodeArray;
11291219
11301220function TPascalParser.ParseRoutine (IsFunction: Boolean; IsConstructor: Boolean = False;
11311221 ForceForward: Boolean = False;
1132- ClsName: string = ' ' ): XTree_Function ;
1222+ ClsName: string = ' ' ): XTree_Node ;
11331223var
11341224 FuncName, TypePrefix: string;
11351225 ArgsNames: TStringArray;
@@ -1166,6 +1256,7 @@ function TPascalParser.ParseRoutine(IsFunction: Boolean; IsConstructor: Boolean
11661256 FullMName, SavedMods: string;
11671257 j: Int32;
11681258 SplitMods: TStringArray;
1259+ S: string;
11691260begin
11701261 Doc := DocPos;
11711262 IsDestructor := (not IsConstructor) and
@@ -1304,18 +1395,19 @@ function TPascalParser.ParseRoutine(IsFunction: Boolean; IsConstructor: Boolean
13041395 if IsForward then
13051396 begin
13061397 Result := XTree_Function.Create(FuncName, ArgsNames, ArgsPass, ArgsTypes, RetType, nil , FContext, Doc);
1307- Result.isConstructor := IsConstructor;
1308- Result.TypeParams := TypeParams;
1309- Result.Annotations := Annotations;
1310- Result.IsForwardDecl := True;
1398+ (Result as XTree_Function).isConstructor := IsConstructor;
1399+ (Result as XTree_Function).TypeParams := TypeParams;
1400+ SetLength((Result as XTree_Function).TypeConstraints, Length((Result as XTree_Function).TypeParams));
1401+ (Result as XTree_Function).Annotations := Annotations;
1402+ (Result as XTree_Function).IsForwardDecl := True;
13111403 if TypePrefix <> ' ' then
13121404 begin
1313- Result.SelfType := FContext.GetType(TypePrefix);
1314- if Result.SelfType = nil then
1405+ ( Result as XTree_Function) .SelfType := FContext.GetType(TypePrefix);
1406+ if ( Result as XTree_Function) .SelfType = nil then
13151407 begin
1316- Result.SelfType := XType.Create(xtUnknown);
1317- Result.SelfType.Name := TypePrefix;
1318- FContext.AddManagedType(Result.SelfType);
1408+ ( Result as XTree_Function) .SelfType := XType.Create(xtUnknown);
1409+ ( Result as XTree_Function) .SelfType.Name := TypePrefix;
1410+ FContext.AddManagedType(( Result as XTree_Function) .SelfType);
13191411 end ;
13201412 end ;
13211413 Exit(Result);
@@ -1324,23 +1416,37 @@ function TPascalParser.ParseRoutine(IsFunction: Boolean; IsConstructor: Boolean
13241416 // -- Body -----------------------------------------------------------------
13251417 Body := XTree_ExprList.Create(FContext, DocPos);
13261418
1327- // Local declarations (var / const / type / label)
1328- while Current.Token in [tkKW_VAR, tkKW_TYPE, tkKW_CONST] do
1329- begin
1330- LocalDecls := ParseDeclarations();
1331- for i := 0 to High(LocalDecls) do Body.List += LocalDecls[i];
1332- end ;
1333-
1334- // Label declarations inside a function
1335- if (Current.Token = tkIDENT) and (XprCase(Current.Value ) = ' label' ) then
1419+ // Local declarations (var / const / type / label / nested routines)
1420+ while True do
13361421 begin
1337- Next();
1338- while Current.Token = tkIDENT do
1422+ if Current.Token in [tkKW_VAR, tkKW_TYPE, tkKW_CONST, tkKW_FUNC] then
13391423 begin
1340- Next();
1341- if not NextIf(tkCOMMA) then Break;
1342- end ;
1343- NextIf(tkSEMI);
1424+ LocalDecls := ParseDeclarations();
1425+ for i := 0 to High(LocalDecls) do Body.List += LocalDecls[i];
1426+ end
1427+ else if Current.Token = tkIDENT then
1428+ begin
1429+ S := XprCase(Current.Value );
1430+ if (S = ' procedure' ) or (S = ' function' ) or (S = ' constructor' ) or (S = ' destructor' ) then
1431+ begin
1432+ LocalDecls := ParseDeclarations();
1433+ for i := 0 to High(LocalDecls) do Body.List += LocalDecls[i];
1434+ end
1435+ else if S = ' label' then
1436+ begin
1437+ Next();
1438+ while Current.Token = tkIDENT do
1439+ begin
1440+ Next();
1441+ if not NextIf(tkCOMMA) then Break;
1442+ end ;
1443+ NextIf(tkSEMI);
1444+ end
1445+ else
1446+ Break; // Reached 'begin' or other statement, break out
1447+ end
1448+ else
1449+ Break;
13441450 end ;
13451451
13461452 if TypePrefix <> ' ' then
@@ -1357,26 +1463,30 @@ function TPascalParser.ParseRoutine(IsFunction: Boolean; IsConstructor: Boolean
13571463 // -- Assemble -------------------------------------------------------------
13581464 Result := XTree_Function.Create(FuncName, ArgsNames, ArgsPass, ArgsTypes,
13591465 RetType, Body, FContext, Doc);
1360- Result.isConstructor := IsConstructor;
1361- Result.TypeParams := TypeParams;
1362- Result.Annotations := Annotations;
1466+ (Result as XTree_Function).isConstructor := IsConstructor;
1467+ (Result as XTree_Function).TypeParams := TypeParams;
1468+ SetLength((Result as XTree_Function).TypeConstraints, Length((Result as XTree_Function).TypeParams));
1469+ (Result as XTree_Function).Annotations := Annotations;
13631470
13641471 // Type-bound method
13651472 if TypePrefix <> ' ' then
13661473 begin
1367- Result.SelfType := FContext.GetType(TypePrefix);
1368- if Result.SelfType = nil then
1474+ ( Result as XTree_Function) .SelfType := FContext.GetType(TypePrefix);
1475+ if ( Result as XTree_Function) .SelfType = nil then
13691476 begin
1370- Result.SelfType := XType.Create(xtUnknown);
1371- Result.SelfType.Name := TypePrefix;
1372- FContext.AddManagedType(Result.SelfType);
1373- FContext.AddType(TypePrefix, Result.SelfType, False); // Make sure it's known!
1477+ (Result as XTree_Function).SelfType := XType.Create(xtUnknown);
1478+ (Result as XTree_Function).SelfType.Name := TypePrefix;
1479+ FContext.AddManagedType((Result as XTree_Function).SelfType);
13741480 end ;
13751481 end ;
13761482
13771483 // If it's a method body bound to a class (and not ForceForward), it's the implementation!
13781484 if (TypePrefix <> ' ' ) and (not ForceForward) then
1379- Result.IsImplementation := True;
1485+ (Result as XTree_Function).IsImplementation := True;
1486+
1487+ // Wrap in XTree_GenericFunction when type params are declared
1488+ if Length(TypeParams) > 0 then
1489+ Result := XTree_GenericFunction.Create(Result, FContext, Doc);
13801490end ;
13811491
13821492// -----------------------------------------------------------------------------
@@ -1919,8 +2029,17 @@ function TPascalParser.ParsePrimary(): XTree_Node;
19192029 if IsPascalUnary(Current.Token) then
19202030 begin
19212031 op := Current; Next();
2032+
2033+ // Manually map Pascal unary operators to Express AST operators
2034+ // to bypass AsOperator raising an exception for unmapped tokens like tkAT.
2035+ if op.Token = tkAT then StepOp := op_Addr
2036+ else if op.Token = tkNOT then StepOp := op_NOT
2037+ else if op.Token = tkMINUS then StepOp := op_Sub
2038+ else if op.Token = tkPLUS then StepOp := op_Add
2039+ else StepOp := AsOperator(op.Token);
2040+
19222041 Result := XTree_UnaryOp.Create(
1923- AsOperator(op.Token) ,
2042+ StepOp ,
19242043 RHSExpr(ParsePrimary(), 8 ),
19252044 FContext, Doc);
19262045 end else
@@ -1935,6 +2054,7 @@ function TPascalParser.RHSExpr(Left: XTree_Node;
19352054 precedence, nextPrecedence: Int8;
19362055 Right: XTree_Node;
19372056 op: TToken;
2057+ binOp, CurrentOP: EOperator;
19382058 Doc: TDocPos;
19392059 clsName: string;
19402060 cArgs: XNodeArray;
@@ -1993,7 +2113,8 @@ function TPascalParser.RHSExpr(Left: XTree_Node;
19932113 Right := RHSExpr(Right, precedence + GetPascalAssoc(op.Token));
19942114 end ;
19952115
1996- case AsOperator(op.Token) of
2116+ CurrentOP := AsOperator(op.Token);
2117+ case CurrentOP of
19972118 op_Dot:
19982119 begin
19992120 if (Right is XTree_Identifier) and (XprCase(XTree_Identifier(Right).Name ) = ' create' ) then
@@ -2020,6 +2141,17 @@ function TPascalParser.RHSExpr(Left: XTree_Node;
20202141 Left := XTree_Field.Create(Left, Right, FContext, Doc);
20212142 end ;
20222143 op_Asgn: Left := XTree_Assign.Create(op_Asgn, Left, Right, FContext, Doc);
2144+ op_AsgnAdd..op_AsgnXOR:
2145+ begin
2146+ binOp := CompoundToBinaryOp(CurrentOP);
2147+ if binOp = op_Unknown then
2148+ FContext.RaiseExceptionFmt(' Unsupported compound assignment operator: %s' ,
2149+ [OperatorToStr(CurrentOP)], DocPos);
2150+ Left := XTree_Assign.Create(
2151+ op_Asgn, Left,
2152+ XTree_BinaryOp.Create(binOp, Left, Right, FContext, DocPos),
2153+ FContext, DocPos);
2154+ end
20232155 else
20242156 Left := XTree_BinaryOp.Create(AsOperator(op.Token), Left, Right, FContext, Doc);
20252157 end ;
0 commit comments