diff --git a/compiler/src/main/pascal/uCodeGenQBE.pas b/compiler/src/main/pascal/uCodeGenQBE.pas index dba924f..acbaa24 100644 --- a/compiler/src/main/pascal/uCodeGenQBE.pas +++ b/compiler/src/main/pascal/uCodeGenQBE.pas @@ -188,10 +188,16 @@ begin VarName := Decl.Names[J]; case Decl.ResolvedType.Kind of tyInteger, tyUInt32, tyBoolean, tyByte: - EmitLine(Format(' %%_var_%s =l alloc4 1', [VarName])); + begin + EmitLine(Format(' %%_var_%s =l alloc4 1', [VarName])); + EmitLine(Format(' storew 0, %%_var_%s', [VarName])); + end; tyInt64: - EmitLine(Format(' %%_var_%s =l alloc8 1', [VarName])); + begin + EmitLine(Format(' %%_var_%s =l alloc8 1', [VarName])); + EmitLine(Format(' storel 0, %%_var_%s', [VarName])); + end; tyString: begin @@ -802,6 +808,14 @@ begin for I := 0 to AMethod.Params.Count - 1 do begin Par := TMethodParam(AMethod.Params[I]); + if Par.IsVarParam then + begin + { Var param arrives as a pointer — spill pointer into a local slot } + EmitLine(Format(' %%_var_%s =l alloc8 1', [Par.ParamName])); + EmitLine(Format(' storel %%_par_%s, %%_var_%s', + [Par.ParamName, Par.ParamName])); + end + else case Par.ResolvedType.Kind of tyInteger, tyUInt32, tyBoolean, tyByte: begin @@ -842,8 +856,11 @@ begin for I := 0 to AMethod.Params.Count - 1 do begin Par := TMethodParam(AMethod.Params[I]); - Sig := Sig + Format(', %s %%_par_%s', - [QbeTypeOf(Par.ResolvedType), Par.ParamName]); + if Par.IsVarParam then + Sig := Sig + Format(', l %%_par_%s', [Par.ParamName]) + else + Sig := Sig + Format(', %s %%_par_%s', + [QbeTypeOf(Par.ResolvedType), Par.ParamName]); end; if IsFunc then @@ -1502,9 +1519,16 @@ begin ArgLine := Format('l %s', [SelfTemp]); for I := 0 to MCallExpr.Args.Count - 1 do begin - Par := TMethodParam(MDecl.Params[I]); - ArgTemp := EmitExpr(TASTExpr(MCallExpr.Args[I])); - ArgLine := ArgLine + Format(', %s %s', [QbeTypeOf(Par.ResolvedType), ArgTemp]); + Par := TMethodParam(MDecl.Params[I]); + if Par.IsVarParam then + { Pass address of the variable directly — do not load through it } + ArgLine := ArgLine + Format(', l %%_var_%s', + [TIdentExpr(TASTExpr(MCallExpr.Args[I])).Name]) + else + begin + ArgTemp := EmitExpr(TASTExpr(MCallExpr.Args[I])); + ArgLine := ArgLine + Format(', %s %s', [QbeTypeOf(Par.ResolvedType), ArgTemp]); + end; end; T := AllocTemp; diff --git a/compiler/src/main/pascal/uSemantic.pas b/compiler/src/main/pascal/uSemantic.pas index 7bfe812..6d895a6 100644 --- a/compiler/src/main/pascal/uSemantic.pas +++ b/compiler/src/main/pascal/uSemantic.pas @@ -1045,7 +1045,7 @@ begin for J := 0 to FieldList.Count - 1 do begin FDecl := TFieldDecl(FieldList[J]); - FldType := FTable.FindType(FDecl.TypeName); + FldType := FindTypeOrInstantiate(FDecl.TypeName); if FldType = nil then SemanticError( Format('Unknown type ''%s'' for field', [FDecl.TypeName]), diff --git a/tests/phase3_milestone.pas b/tests/phase3_milestone.pas new file mode 100644 index 0000000..312e480 --- /dev/null +++ b/tests/phase3_milestone.pas @@ -0,0 +1,250 @@ +program Phase3Milestone; + +{ Phase 3 milestone: exercises TList and TDictionary. + Must produce correct output and zero valgrind leaks. } + +type + TIntList = class + FData: ^Integer; + FCount: Integer; + FCapacity: Integer; + procedure Grow; + procedure Add(Value: Integer); + function Get(AIndex: Integer): Integer; + procedure Delete(AIndex: Integer); + procedure Free; + property Count: Integer read FCount; + end; + + TStrIntDict = class + FKeys: ^string; + FValues: ^Integer; + FCount: Integer; + FCapacity: Integer; + procedure Grow; + function FindKey(Key: string): Integer; + procedure Add(Key: string; Value: Integer); + function TryGetValue(Key: string; var Value: Integer): Boolean; + function ContainsKey(Key: string): Boolean; + procedure Remove(Key: string); + procedure Free; + property Count: Integer read FCount; + end; + +procedure TIntList.Grow; +var + NewCap: Integer; +begin + if Self.FCapacity = 0 then + NewCap := 4 + else + NewCap := Self.FCapacity * 2; + Self.FData := ReallocMem(Self.FData, NewCap * SizeOf(Integer)); + Self.FCapacity := NewCap +end; + +procedure TIntList.Add(Value: Integer); +var + Dest: ^Integer; +begin + if Self.FCount = Self.FCapacity then + Self.Grow; + Dest := Self.FData + Self.FCount * SizeOf(Integer); + Dest^ := Value; + Self.FCount := Self.FCount + 1 +end; + +function TIntList.Get(AIndex: Integer): Integer; +var + Src: ^Integer; +begin + Src := Self.FData + AIndex * SizeOf(Integer); + Result := Src^ +end; + +procedure TIntList.Delete(AIndex: Integer); +var + Src: ^Integer; + Dst: ^Integer; + I: Integer; +begin + I := AIndex; + while I < Self.FCount - 1 do + begin + Dst := Self.FData + I * SizeOf(Integer); + Src := Self.FData + (I + 1) * SizeOf(Integer); + Dst^ := Src^; + I := I + 1 + end; + Self.FCount := Self.FCount - 1 +end; + +procedure TIntList.Free; +begin + FreeMem(Self.FData); + FreeMem(Self) +end; + +procedure TStrIntDict.Grow; +var + NewCap: Integer; +begin + if Self.FCapacity = 0 then + NewCap := 8 + else + NewCap := Self.FCapacity * 2; + Self.FKeys := ReallocMem(Self.FKeys, NewCap * SizeOf(string)); + Self.FValues := ReallocMem(Self.FValues, NewCap * SizeOf(Integer)); + Self.FCapacity := NewCap +end; + +function TStrIntDict.FindKey(Key: string): Integer; +var + I: Integer; + Ptr: ^string; +begin + Result := -1; + I := 0; + while I < Self.FCount do + begin + Ptr := Self.FKeys + I * SizeOf(string); + if Ptr^ = Key then + begin + Result := I; + I := Self.FCount + end + else + I := I + 1 + end +end; + +procedure TStrIntDict.Add(Key: string; Value: Integer); +var + Idx: Integer; + KPtr: ^string; + VPtr: ^Integer; +begin + Idx := Self.FindKey(Key); + if Idx >= 0 then + begin + VPtr := Self.FValues + Idx * SizeOf(Integer); + VPtr^ := Value + end + else + begin + if Self.FCount = Self.FCapacity then + Self.Grow; + KPtr := Self.FKeys + Self.FCount * SizeOf(string); + VPtr := Self.FValues + Self.FCount * SizeOf(Integer); + KPtr^ := Key; + VPtr^ := Value; + Self.FCount := Self.FCount + 1 + end +end; + +function TStrIntDict.TryGetValue(Key: string; var Value: Integer): Boolean; +var + Idx: Integer; + VPtr: ^Integer; +begin + Idx := Self.FindKey(Key); + if Idx >= 0 then + begin + VPtr := Self.FValues + Idx * SizeOf(Integer); + Value := VPtr^; + Result := True + end + else + Result := False +end; + +function TStrIntDict.ContainsKey(Key: string): Boolean; +begin + Result := Self.FindKey(Key) >= 0 +end; + +procedure TStrIntDict.Remove(Key: string); +var + Idx: Integer; + I: Integer; + KDst: ^string; + KSrc: ^string; + VDst: ^Integer; + VSrc: ^Integer; +begin + Idx := Self.FindKey(Key); + if Idx >= 0 then + begin + I := Idx; + while I < Self.FCount - 1 do + begin + KDst := Self.FKeys + I * SizeOf(string); + KSrc := Self.FKeys + (I + 1) * SizeOf(string); + VDst := Self.FValues + I * SizeOf(Integer); + VSrc := Self.FValues + (I + 1) * SizeOf(Integer); + KDst^ := KSrc^; + VDst^ := VSrc^; + I := I + 1 + end; + Self.FCount := Self.FCount - 1 + end +end; + +procedure TStrIntDict.Free; +begin + FreeMem(Self.FKeys); + FreeMem(Self.FValues); + FreeMem(Self) +end; + +var + List: TIntList; + Dict: TStrIntDict; + V: Integer; + Found: Boolean; + +begin + { --- TList --- } + List := TIntList.Create; + List.Add(10); + List.Add(20); + List.Add(30); + List.Add(40); + List.Add(50); + + Write('list.count='); WriteLn(List.Count); { 5 } + Write('list[0]='); WriteLn(List.Get(0)); { 10 } + Write('list[4]='); WriteLn(List.Get(4)); { 50 } + + List.Delete(1); + Write('count_after_delete='); WriteLn(List.Count); { 4 } + Write('list[1]_after_delete='); WriteLn(List.Get(1)); { 30 } + + List.Free; + + { --- TDictionary --- } + Dict := TStrIntDict.Create; + Dict.Add('alpha', 1); + Dict.Add('beta', 2); + Dict.Add('gamma', 3); + Dict.Add('delta', 4); + + Write('dict.count='); WriteLn(Dict.Count); { 4 } + + Found := Dict.TryGetValue('beta', V); + Write('beta='); WriteLn(V); { 2 } + + Found := Dict.ContainsKey('gamma'); + Write('has_gamma='); WriteLn(Found); { 1 } + + Dict.Add('beta', 99); + Found := Dict.TryGetValue('beta', V); + Write('beta_after_update='); WriteLn(V); { 99 } + + Dict.Remove('alpha'); + Write('count_after_remove='); WriteLn(Dict.Count); { 3 } + Found := Dict.ContainsKey('alpha'); + Write('has_alpha_after_remove='); WriteLn(Found); { 0 } + + Dict.Free +end.