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.
162 lines
3.5 KiB
ObjectPascal
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.
|