diff --git a/compiler/src/main/pascal/Blaise.pas b/compiler/src/main/pascal/Blaise.pas index 890fe7d..465e70f 100644 --- a/compiler/src/main/pascal/Blaise.pas +++ b/compiler/src/main/pascal/Blaise.pas @@ -294,6 +294,7 @@ begin SearchPaths.Free; Exit; end; + GTarget := Target; end else if (Arg = '--help') or (Arg = '-h') then begin diff --git a/compiler/src/main/pascal/blaise.codegen.target.pas b/compiler/src/main/pascal/blaise.codegen.target.pas index d70f3b7..a323fe7 100644 --- a/compiler/src/main/pascal/blaise.codegen.target.pas +++ b/compiler/src/main/pascal/blaise.codegen.target.pas @@ -60,6 +60,14 @@ function TargetName(const ATarget: TTargetDesc): string; { True when the native backend can actually generate code for this target. } function TargetHasNativeBackend(const ATarget: TTargetDesc): Boolean; +{ Platform constants derived from the target OS. } +function TargetLineEnding(const ATarget: TTargetDesc): string; +function TargetDirectorySeparator(const ATarget: TTargetDesc): string; +function TargetPathSeparator(const ATarget: TTargetDesc): string; + +var + GTarget: TTargetDesc; + implementation uses @@ -136,4 +144,34 @@ begin Result := (ATarget.OS = osLinux) and (ATarget.CPU = cpuX86_64); end; +function TargetLineEnding(const ATarget: TTargetDesc): string; +begin + case ATarget.OS of + osWindows: Result := #13#10; + else + Result := #10; + end; +end; + +function TargetDirectorySeparator(const ATarget: TTargetDesc): string; +begin + case ATarget.OS of + osWindows: Result := '\'; + else + Result := '/'; + end; +end; + +function TargetPathSeparator(const ATarget: TTargetDesc): string; +begin + case ATarget.OS of + osWindows: Result := ';'; + else + Result := ':'; + end; +end; + +initialization + GTarget := HostTarget; + end. diff --git a/compiler/src/main/pascal/uSymbolTable.pas b/compiler/src/main/pascal/uSymbolTable.pas index 6676ff7..864a90e 100644 --- a/compiler/src/main/pascal/uSymbolTable.pas +++ b/compiler/src/main/pascal/uSymbolTable.pas @@ -560,6 +560,9 @@ function MangleUnitPrefix(const AUnitName: string): string; implementation +uses + blaise.codegen.target; + { ------------------------------------------------------------------ } { TUsesChainProvider } { ------------------------------------------------------------------ } @@ -1479,19 +1482,17 @@ begin Sym.ConstValue := 2147483647; Define(Sym); - { System string/path constants — defined in system.pas; pre-seeded here - so they resolve even before system.pas is loaded as a unit. } + { Platform constants — values derived from the compilation target (GTarget). + Defined in system.pas; pre-seeded here so they resolve even before + system.pas is loaded as a unit. } Sym := TSymbol.Create('LineEnding', skConstant, FTypeString); - Sym.ConstString := #10; - Define(Sym); - Sym := TSymbol.Create('sLineBreak', skConstant, FTypeString); - Sym.ConstString := #10; + Sym.ConstString := TargetLineEnding(GTarget); Define(Sym); Sym := TSymbol.Create('DirectorySeparator', skConstant, FTypeString); - Sym.ConstString := '/'; + Sym.ConstString := TargetDirectorySeparator(GTarget); Define(Sym); Sym := TSymbol.Create('PathSeparator', skConstant, FTypeString); - Sym.ConstString := ':'; + Sym.ConstString := TargetPathSeparator(GTarget); Define(Sym); { Built-in I/O procedures } diff --git a/compiler/src/test/pascal/cp.test.e2e.sysutils.pas b/compiler/src/test/pascal/cp.test.e2e.sysutils.pas index df1eeb7..d807d4d 100644 --- a/compiler/src/test/pascal/cp.test.e2e.sysutils.pas +++ b/compiler/src/test/pascal/cp.test.e2e.sysutils.pas @@ -45,7 +45,7 @@ type procedure TestRun_SetCurrentDir_ChangesDir; procedure TestRun_ExtractFileExt_ReturnsExt; procedure TestRun_BoolToStr_TrueAndFalse; - procedure TestRun_SysUtils_LineEndingConst; + procedure TestRun_PlatformConstants; procedure TestRun_GetCurrentDir_ReturnsNonEmpty; end; @@ -533,13 +533,13 @@ const end. '''; - SrcLineEndingConst = + SrcPlatformConstants = ''' program P; - uses SysUtils; begin - WriteLn(sLineBreak = #10); - WriteLn(LineEnding = #10) + WriteLn(LineEnding = #10); + WriteLn(DirectorySeparator = '/'); + WriteLn(PathSeparator = ':') end. '''; @@ -647,20 +647,21 @@ begin end; end; -procedure TE2ESysUtilsTests.TestRun_SysUtils_LineEndingConst; +procedure TE2ESysUtilsTests.TestRun_PlatformConstants; var Output: string; RCode: Integer; Lines: TStringList; begin if not ToolchainAvailable then begin Ignore('toolchain unavailable'); Exit; end; - AssertTrue('compile+run', CompileAndRunWithRTL(SrcLineEndingConst, Output, RCode)); + AssertTrue('compile+run', CompileAndRunWithRTL(SrcPlatformConstants, Output, RCode)); AssertEquals('exit code 0', 0, RCode); Lines := TStringList.Create; try Lines.Text := Trim(Output); - AssertEquals('sLineBreak = #10', '1', Lines.Strings[0]); - AssertEquals('LineEnding = #10', '1', Lines.Strings[1]); + AssertEquals('LineEnding = #10', '1', Lines.Strings[0]); + AssertEquals('DirectorySeparator = /', '1', Lines.Strings[1]); + AssertEquals('PathSeparator = :', '1', Lines.Strings[2]); finally Lines.Free; end; diff --git a/docs/language-rationale.adoc b/docs/language-rationale.adoc index 467f71d..27abbd5 100644 --- a/docs/language-rationale.adoc +++ b/docs/language-rationale.adoc @@ -3135,3 +3135,40 @@ string `TFoo<>` in `TFieldAccessExpr.RecordName`. The semantic pass — in which replaces the sentinel with the full concrete type name taken from `ResolvedLhsType.Name`. Subsequent semantic analysis proceeds identically to an explicit constructor call. + + +== Platform constants — one name per concept + +Delphi and FPC carry multiple aliases for the same platform constant: + +* `LineEnding` (FPC), `sLineBreak` (Delphi), and sometimes `LineBreak` +* `DirectorySeparator` (both), `PathDelim` (Delphi SysUtils alias) +* `PathSeparator` (both) — no alias, the one exception + +Blaise retains exactly three names, one per concept: + +[cols="1,1,1"] +|=== +| Constant | POSIX value | Windows value + +| `LineEnding` +| `#10` +| `#13#10` + +| `DirectorySeparator` +| `/` +| `\` + +| `PathSeparator` +| `:` +| `;` +|=== + +*Dropped:* `sLineBreak`, `PathDelim`. They were Delphi compatibility aliases +that added no meaning — two names for the same value is a maintenance trap, not +backwards compatibility. + +All three constants are defined in `system.pas` and pre-seeded as compiler +built-ins in `RegisterBuiltins`. Their values are derived from the compilation +target (`GTarget` in `blaise.codegen.target`), so cross-compilation to a +different OS produces the correct constants without conditional compilation. diff --git a/runtime/src/main/pascal/system.pas b/runtime/src/main/pascal/system.pas index 22f9226..f319905 100644 --- a/runtime/src/main/pascal/system.pas +++ b/runtime/src/main/pascal/system.pas @@ -87,17 +87,14 @@ type { ------------------------------------------------------------------ } const - { Line ending for the current platform. POSIX = #10, Windows = #13#10. - Blaise currently targets POSIX only. } + { Line ending for the current platform. POSIX = #10, Windows = #13#10. + Set at compile time based on the target platform. } LineEnding = #10; - { Delphi compatibility alias for LineEnding. } - sLineBreak = LineEnding; - - { Directory separator character. } + { Directory separator character. POSIX = '/', Windows = '\'. } DirectorySeparator = '/'; - { PATH environment variable separator. } + { PATH environment variable separator. POSIX = ':', Windows = ';'. } PathSeparator = ':'; { ------------------------------------------------------------------ } diff --git a/stdlib/src/main/pascal/sysutils.pas b/stdlib/src/main/pascal/sysutils.pas index 084c5d1..7a52a31 100644 --- a/stdlib/src/main/pascal/sysutils.pas +++ b/stdlib/src/main/pascal/sysutils.pas @@ -10,11 +10,12 @@ unit SysUtils; // Blaise RTL — SysUtils unit. // -// Provides the Exception base class, PathDelim (Delphi compat alias for -// DirectorySeparator), and the BoolToStr helper. +// Provides the Exception base class and the BoolToStr helper. // -// LineEnding, sLineBreak, DirectorySeparator, and PathSeparator are defined -// in system.pas — they are platform fundamentals, not SysUtils concerns. +// Platform constants (LineEnding, DirectorySeparator, PathSeparator) are +// defined in system.pas — they are platform fundamentals, not SysUtils +// concerns. Blaise does not carry the Delphi/FPC legacy aliases +// (sLineBreak, PathDelim). // // Functions that are already compiler built-ins (FileExists, DeleteFile, // RenameFile, SetCurrentDir, ExtractFileExt, IntToStr, StrToInt, Format, @@ -24,10 +25,6 @@ unit SysUtils; interface -const - { Delphi compatibility alias for system.DirectorySeparator. } - PathDelim = '/'; - type Exception = class FMessage: string;