blaise/tests/phase2_milestone.pas
Graeme Geldenhuys 5894411a35 chore(license): relicense from BSD-3-Clause to Apache 2.0 + Runtime Library Exception
Adopts the Swift/LLVM model: Apache License 2.0 with the Runtime Library
Exception text used verbatim by the Swift project. SPDX identifier:
Apache-2.0 WITH Swift-exception.

Apache 2.0 brings an explicit patent grant and patent-retaliation clause
that BSD-3 lacks. The Runtime Library Exception ensures binaries
produced by the Blaise compiler do not inherit attribution obligations
from the linked-in RTL.

* LICENSE — full Apache 2.0 + RLE text (replaces the deleted LICENCE).
* NOTICE — project header plus QBE attribution (MIT, vendored).
* docs/language-rationale.adoc — new Project Governance section
  capturing the decision, alternatives considered, and rationale.
* SPDX headers updated across all .pas, .pp, .inc, .c source files,
  build scripts, PasBuild plugins, and the Makefile.
* project.xml license field updated.
* tools/migrate_full.py HEADER template updated so generated
  self-hosting source carries the new licence.
2026-05-03 19:45:29 +01:00

162 lines
3.5 KiB
ObjectPascal

{
Blaise - An Object Pascal Compiler
Copyright (c) 2026 Graeme Geldenhuys
SPDX-License-Identifier: Apache-2.0 WITH Swift-exception
Licensed under the Apache License v2.0 with Runtime Library Exception.
See LICENSE file in the project root for full license terms.
}
program Phase2Milestone;
{ Phase 2 milestone: singly-linked list using TObject descendants.
Exercises:
- Class inheritance (TNode → TMarkedNode)
- Virtual method dispatch (GetTag override)
- Properties (Value, Next, Count, Head)
- Self-referential class field (FNext: TNode)
- try/finally for guaranteed cleanup
- 'is' type test
Must compile, produce correct output, and show zero valgrind leaks. }
type
{ Base list node: integer value + link to next }
TNode = class
FValue: Integer;
FNext: TNode;
function GetTag: Integer; virtual;
property Value: Integer read FValue;
property Next: TNode read FNext;
end;
{ Marked node: identical to TNode but GetTag returns 1 instead of 0 }
TMarkedNode = class(TNode)
function GetTag: Integer; override;
end;
{ Singly-linked list, push-at-front / pop-from-front }
TLinkedList = class
FHead: TNode;
FCount: Integer;
procedure Push(Value: Integer);
procedure PushMarked(Value: Integer);
function Pop: Integer;
procedure Walk;
procedure Clear;
property Count: Integer read FCount;
property Head: TNode read FHead;
end;
{ ---- TNode ---- }
function TNode.GetTag: Integer;
begin
Result := 0
end;
{ ---- TMarkedNode ---- }
function TMarkedNode.GetTag: Integer;
begin
Result := 1
end;
{ ---- TLinkedList ---- }
procedure TLinkedList.Push(Value: Integer);
var
N: TNode;
begin
N := TNode.Create;
N.FValue := Value;
N.FNext := Self.FHead;
Self.FHead := N;
Self.FCount := Self.FCount + 1
end;
procedure TLinkedList.PushMarked(Value: Integer);
var
N: TMarkedNode;
begin
N := TMarkedNode.Create;
N.FValue := Value;
N.FNext := Self.FHead;
Self.FHead := N;
Self.FCount := Self.FCount + 1
end;
function TLinkedList.Pop: Integer;
var
N: TNode;
begin
N := Self.FHead;
Result := N.FValue;
Self.FHead := N.FNext;
Self.FCount := Self.FCount - 1;
N.Free
end;
procedure TLinkedList.Walk;
var
N: TNode;
Marked: Boolean;
begin
N := Self.FHead;
while N <> nil do
begin
WriteLn(' value=', N.Value);
WriteLn(' tag=', N.GetTag());
Marked := N is TMarkedNode;
WriteLn(' marked=', Marked);
N := N.Next
end
end;
procedure TLinkedList.Clear;
var
N: TNode;
Next: TNode;
begin
N := Self.FHead;
while N <> nil do
begin
Next := N.FNext;
N.Free;
N := Next
end;
Self.FHead := nil;
Self.FCount := 0
end;
{ ---- Main ---- }
var
List: TLinkedList;
V: Integer;
begin
List := TLinkedList.Create;
try
{ Build list: push 10, 20 (plain), 30 (marked), 40 (plain)
After four pushes the front is 40 → 30(marked) → 20 → 10 }
List.Push(10);
List.Push(20);
List.PushMarked(30);
List.Push(40);
WriteLn('count=', List.Count); { 4 }
WriteLn('--- walk ---');
List.Walk; { 40/tag0, 30/tag1/marked, 20/tag0, 10/tag0 }
{ Pop two values off the front }
V := List.Pop();
WriteLn('pop=', V); { 40 }
V := List.Pop();
WriteLn('pop=', V); { 30 }
WriteLn('count_after_pops=', List.Count); { 2 }
finally
List.Clear;
List.Free
end
end.