2026-04-22 21:00:46 +03:00
|
|
|
{
|
|
|
|
|
Blaise - An Object Pascal Compiler
|
|
|
|
|
Copyright (c) 2026 Graeme Geldenhuys
|
2026-05-03 21:45:29 +03:00
|
|
|
SPDX-License-Identifier: Apache-2.0 WITH Swift-exception
|
|
|
|
|
Licensed under the Apache License v2.0 with Runtime Library Exception.
|
2026-04-22 21:00:46 +03:00
|
|
|
See LICENSE file in the project root for full license terms.
|
|
|
|
|
}
|
|
|
|
|
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
unit cp.test.codegen;
|
|
|
|
|
|
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
|
|
uses
|
|
|
|
|
Classes, SysUtils, fpcunit, testregistry,
|
Add Phase 2: record/class types, ARC strings, RTL stubs, and grammar doc
Symbol table:
- Added tyClass kind and NewClassType factory; TRecordTypeDesc now
accepts an optional kind parameter so records and classes share the
same descriptor with distinct semantics.
Semantic analyser:
- AnalyseTypeDecls runs before PushScope so type symbols land in global
scope and survive PopScope.
- Handles TRecordTypeDef and TClassTypeDef; sets IsConstructorCall on
TypeName.Create expressions and IsClassAccess on class-variable field
access and assignment nodes.
Code generator (QBE IR):
- Class variables: 8-byte pointer slot, zeroed on entry.
- Constructor calls: malloc(sizeof fields), store pointer.
- Class field access/write: load pointer, add field offset, load/store.
- ARC string assignment: AddRef new value, Release old value, then store.
- Block exit: Release every string variable in scope (EmitStringCleanup).
Lexer / Parser / AST:
- Added tkClass keyword and ParseClassDef; FieldDecl parsing refactored
into ParseFieldDecl(AFields) shared by both record and class.
- AST gains TClassTypeDef, and IsConstructorCall/IsClassAccess flags on
TFieldAccessExpr and TFieldAssignment.
RTL:
- blaise_arc.c: Phase 2 no-op stubs for _StringAddRef / _StringRelease.
- rtl/Makefile: builds blaise_rtl.a; `make install` copies it next to
the compiler binary for automatic discovery by FindRTL.
- Blaise.pas driver: FindRTL checks BLAISE_RTL env var then binary dir;
links the RTL archive when present.
Tests:
- 180 unit tests (records ×23, classes ×22, ARC ×9, codegen ×9, …).
- 4 end-to-end integration tests in tests/integration/test_arc_strings.sh
covering string assignment, two-var cleanup, reassignment cycle, and
empty-program linkage.
Docs:
- design.adoc updated with Phase 2 implementation status table.
- docs/grammar.ebnf: new authoritative EBNF grammar for the Blaise
language as implemented, including ARC semantic annotations.
2026-04-20 21:04:12 +03:00
|
|
|
uLexer, uParser, uAST, uSemantic, uCodeGenQBE;
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
|
|
|
|
|
type
|
|
|
|
|
TCodeGenTests = class(TTestCase)
|
|
|
|
|
private
|
|
|
|
|
function GenerateIR(const ASrc: string): string;
|
|
|
|
|
function IRContains(const AIR, AFragment: string): Boolean;
|
|
|
|
|
published
|
|
|
|
|
{ Data sections }
|
|
|
|
|
procedure TestHelloWorld_HasStrLitData;
|
2026-05-01 19:22:07 +03:00
|
|
|
procedure TestHelloWorld_UsesSysWriteStr;
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
|
|
|
|
|
{ Main function structure }
|
|
|
|
|
procedure TestOutput_HasMainFunction;
|
|
|
|
|
procedure TestOutput_HasRetZero;
|
|
|
|
|
|
|
|
|
|
{ WriteLn }
|
2026-05-01 19:22:07 +03:00
|
|
|
procedure TestWriteLn_NoArgs_CallsSysWriteNewline;
|
|
|
|
|
procedure TestWriteLn_StringLit_CallsSysWriteStr;
|
|
|
|
|
procedure TestWriteLn_IntExpr_CallsSysWriteInt;
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
|
|
|
|
|
{ Variables and assignment }
|
|
|
|
|
procedure TestIntVar_HasAlloc;
|
|
|
|
|
procedure TestAssignment_HasStorew;
|
|
|
|
|
procedure TestAssignment_LoadAndStore;
|
|
|
|
|
|
|
|
|
|
{ Arithmetic }
|
|
|
|
|
procedure TestAdd_EmitsAddInstruction;
|
|
|
|
|
procedure TestMul_EmitsMulInstruction;
|
|
|
|
|
|
|
|
|
|
{ Header comment }
|
|
|
|
|
procedure TestOutput_HasSourceComment;
|
2026-04-22 18:37:31 +03:00
|
|
|
|
2026-04-22 18:40:17 +03:00
|
|
|
{ String equality }
|
|
|
|
|
procedure TestStringEq_EmitsStringEquals;
|
|
|
|
|
procedure TestStringNe_EmitsStringEqualsNegated;
|
|
|
|
|
procedure TestStringEq_SemanticCompiles;
|
|
|
|
|
|
2026-04-22 18:37:31 +03:00
|
|
|
{ True / False built-in constants }
|
|
|
|
|
procedure TestTrue_EmitsCopyOne;
|
|
|
|
|
procedure TestFalse_EmitsCopyZero;
|
|
|
|
|
procedure TestTrue_AssignToBoolVar;
|
|
|
|
|
procedure TestFalse_AssignToBoolVar;
|
|
|
|
|
procedure TestTrue_InIfCondition;
|
|
|
|
|
procedure TestBoolFunc_ReturnTrue;
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
|
|
|
|
function TCodeGenTests.GenerateIR(const ASrc: string): string;
|
|
|
|
|
var
|
|
|
|
|
L: TLexer;
|
|
|
|
|
P: TParser;
|
|
|
|
|
Pr: TProgram;
|
Add Phase 2: record/class types, ARC strings, RTL stubs, and grammar doc
Symbol table:
- Added tyClass kind and NewClassType factory; TRecordTypeDesc now
accepts an optional kind parameter so records and classes share the
same descriptor with distinct semantics.
Semantic analyser:
- AnalyseTypeDecls runs before PushScope so type symbols land in global
scope and survive PopScope.
- Handles TRecordTypeDef and TClassTypeDef; sets IsConstructorCall on
TypeName.Create expressions and IsClassAccess on class-variable field
access and assignment nodes.
Code generator (QBE IR):
- Class variables: 8-byte pointer slot, zeroed on entry.
- Constructor calls: malloc(sizeof fields), store pointer.
- Class field access/write: load pointer, add field offset, load/store.
- ARC string assignment: AddRef new value, Release old value, then store.
- Block exit: Release every string variable in scope (EmitStringCleanup).
Lexer / Parser / AST:
- Added tkClass keyword and ParseClassDef; FieldDecl parsing refactored
into ParseFieldDecl(AFields) shared by both record and class.
- AST gains TClassTypeDef, and IsConstructorCall/IsClassAccess flags on
TFieldAccessExpr and TFieldAssignment.
RTL:
- blaise_arc.c: Phase 2 no-op stubs for _StringAddRef / _StringRelease.
- rtl/Makefile: builds blaise_rtl.a; `make install` copies it next to
the compiler binary for automatic discovery by FindRTL.
- Blaise.pas driver: FindRTL checks BLAISE_RTL env var then binary dir;
links the RTL archive when present.
Tests:
- 180 unit tests (records ×23, classes ×22, ARC ×9, codegen ×9, …).
- 4 end-to-end integration tests in tests/integration/test_arc_strings.sh
covering string assignment, two-var cleanup, reassignment cycle, and
empty-program linkage.
Docs:
- design.adoc updated with Phase 2 implementation status table.
- docs/grammar.ebnf: new authoritative EBNF grammar for the Blaise
language as implemented, including ARC semantic annotations.
2026-04-20 21:04:12 +03:00
|
|
|
A: TSemanticAnalyser;
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
CG: TCodeGenQBE;
|
|
|
|
|
begin
|
|
|
|
|
L := TLexer.Create(ASrc);
|
|
|
|
|
P := TParser.Create(L);
|
|
|
|
|
Pr := P.Parse;
|
Add Phase 2: record/class types, ARC strings, RTL stubs, and grammar doc
Symbol table:
- Added tyClass kind and NewClassType factory; TRecordTypeDesc now
accepts an optional kind parameter so records and classes share the
same descriptor with distinct semantics.
Semantic analyser:
- AnalyseTypeDecls runs before PushScope so type symbols land in global
scope and survive PopScope.
- Handles TRecordTypeDef and TClassTypeDef; sets IsConstructorCall on
TypeName.Create expressions and IsClassAccess on class-variable field
access and assignment nodes.
Code generator (QBE IR):
- Class variables: 8-byte pointer slot, zeroed on entry.
- Constructor calls: malloc(sizeof fields), store pointer.
- Class field access/write: load pointer, add field offset, load/store.
- ARC string assignment: AddRef new value, Release old value, then store.
- Block exit: Release every string variable in scope (EmitStringCleanup).
Lexer / Parser / AST:
- Added tkClass keyword and ParseClassDef; FieldDecl parsing refactored
into ParseFieldDecl(AFields) shared by both record and class.
- AST gains TClassTypeDef, and IsConstructorCall/IsClassAccess flags on
TFieldAccessExpr and TFieldAssignment.
RTL:
- blaise_arc.c: Phase 2 no-op stubs for _StringAddRef / _StringRelease.
- rtl/Makefile: builds blaise_rtl.a; `make install` copies it next to
the compiler binary for automatic discovery by FindRTL.
- Blaise.pas driver: FindRTL checks BLAISE_RTL env var then binary dir;
links the RTL archive when present.
Tests:
- 180 unit tests (records ×23, classes ×22, ARC ×9, codegen ×9, …).
- 4 end-to-end integration tests in tests/integration/test_arc_strings.sh
covering string assignment, two-var cleanup, reassignment cycle, and
empty-program linkage.
Docs:
- design.adoc updated with Phase 2 implementation status table.
- docs/grammar.ebnf: new authoritative EBNF grammar for the Blaise
language as implemented, including ARC semantic annotations.
2026-04-20 21:04:12 +03:00
|
|
|
A := TSemanticAnalyser.Create;
|
|
|
|
|
try
|
|
|
|
|
A.Analyse(Pr);
|
|
|
|
|
finally
|
|
|
|
|
A.Free;
|
|
|
|
|
end;
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
CG := TCodeGenQBE.Create;
|
|
|
|
|
try
|
|
|
|
|
CG.Generate(Pr);
|
|
|
|
|
Result := CG.GetOutput;
|
|
|
|
|
finally
|
|
|
|
|
CG.Free;
|
|
|
|
|
Pr.Free;
|
|
|
|
|
P.Free;
|
|
|
|
|
L.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function TCodeGenTests.IRContains(const AIR, AFragment: string): Boolean;
|
|
|
|
|
begin
|
|
|
|
|
Result := Pos(AFragment, AIR) > 0;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{ Data sections }
|
|
|
|
|
|
|
|
|
|
procedure TCodeGenTests.TestHelloWorld_HasStrLitData;
|
|
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR('program P; begin WriteLn(''Hello'') end.');
|
|
|
|
|
AssertTrue('Has str data',
|
|
|
|
|
IRContains(IR, 'data $__s0'));
|
|
|
|
|
AssertTrue('Contains Hello',
|
|
|
|
|
IRContains(IR, '"Hello"'));
|
|
|
|
|
end;
|
|
|
|
|
|
2026-05-01 19:22:07 +03:00
|
|
|
procedure TCodeGenTests.TestHelloWorld_UsesSysWriteStr;
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR('program P; begin WriteLn(''Hello'') end.');
|
2026-05-01 19:22:07 +03:00
|
|
|
AssertTrue('Calls _SysWriteStr',
|
|
|
|
|
IRContains(IR, 'call $_SysWriteStr('));
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{ Main function structure }
|
|
|
|
|
|
|
|
|
|
procedure TCodeGenTests.TestOutput_HasMainFunction;
|
|
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR('program P; begin end.');
|
|
|
|
|
AssertTrue('Has export function $main',
|
Close self-hosting gaps: multi-section blocks, file I/O, CLI args, process
Parser: allow any number of type/var/procedure/function sections in any
order within a single block. Required for single-file concatenation of
compiler units during self-hosting migration.
RTL (blaise_io.c): _SetArgs, _ParamCount, _ParamStr, _ReadFile, _WriteFile,
_AppendFile, _FileExists, _GetEnvVar, _Exec, _Halt. All exposed as Blaise
builtins via uSymbolTable/uSemantic/uCodeGenQBE.
$main now emits (w %argc, l %argv) and calls _SetArgs at startup so
ParamStr/ParamCount work at runtime.
TIdentExpr: IsNoArgFuncCall flag for builtin functions called without parens
(e.g. ParamCount without ()). Codegen synthesises a temporary TFuncCallExpr
so the existing builtin dispatch handles it transparently.
IR comment: removed stale "(Phase 2)" tag.
815 tests pass, zero Valgrind errors.
2026-04-23 15:00:34 +03:00
|
|
|
IRContains(IR, 'export function w $main('));
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TCodeGenTests.TestOutput_HasRetZero;
|
|
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR('program P; begin end.');
|
|
|
|
|
AssertTrue('Has ret 0', IRContains(IR, 'ret 0'));
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{ WriteLn }
|
|
|
|
|
|
2026-05-01 19:22:07 +03:00
|
|
|
procedure TCodeGenTests.TestWriteLn_NoArgs_CallsSysWriteNewline;
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR('program P; begin WriteLn() end.');
|
2026-05-01 19:22:07 +03:00
|
|
|
AssertTrue('Calls _SysWriteNewline',
|
|
|
|
|
IRContains(IR, 'call $_SysWriteNewline(w 1)'));
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
end;
|
|
|
|
|
|
2026-05-01 19:22:07 +03:00
|
|
|
procedure TCodeGenTests.TestWriteLn_StringLit_CallsSysWriteStr;
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR('program P; begin WriteLn(''Hi'') end.');
|
2026-05-01 19:22:07 +03:00
|
|
|
AssertTrue('Calls _SysWriteStr with string pointer',
|
|
|
|
|
IRContains(IR, 'call $_SysWriteStr(w 1,'));
|
|
|
|
|
AssertTrue('Calls _SysWriteNewline for line ending',
|
|
|
|
|
IRContains(IR, 'call $_SysWriteNewline(w 1)'));
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
end;
|
|
|
|
|
|
2026-05-01 19:22:07 +03:00
|
|
|
procedure TCodeGenTests.TestWriteLn_IntExpr_CallsSysWriteInt;
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR('program P; begin WriteLn(42) end.');
|
2026-05-01 19:22:07 +03:00
|
|
|
AssertTrue('Calls _SysWriteInt',
|
|
|
|
|
IRContains(IR, 'call $_SysWriteInt(w 1,'));
|
|
|
|
|
AssertTrue('Calls _SysWriteNewline for line ending',
|
|
|
|
|
IRContains(IR, 'call $_SysWriteNewline(w 1)'));
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{ Variables and assignment }
|
|
|
|
|
|
|
|
|
|
procedure TCodeGenTests.TestIntVar_HasAlloc;
|
|
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR('program P; var x: Integer; begin end.');
|
2026-04-24 02:21:43 +03:00
|
|
|
{ Program-level var is a data-section global, not a stack alloc }
|
|
|
|
|
AssertTrue('Has data decl for x',
|
|
|
|
|
IRContains(IR, 'data $x'));
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TCodeGenTests.TestAssignment_HasStorew;
|
|
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR(
|
|
|
|
|
'program P; var n: Integer; begin n := 7 end.');
|
|
|
|
|
AssertTrue('Has storew', IRContains(IR, 'storew'));
|
2026-04-24 02:21:43 +03:00
|
|
|
{ Program-level var n is a global: store goes to $n }
|
|
|
|
|
AssertTrue('Stores to n', IRContains(IR, 'storew %_t0, $n'));
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TCodeGenTests.TestAssignment_LoadAndStore;
|
|
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR(
|
|
|
|
|
'program P; var x, y: Integer; begin x := 1; y := x end.');
|
2026-04-24 02:21:43 +03:00
|
|
|
{ Program-level vars x, y are globals: load/store use $name }
|
|
|
|
|
AssertTrue('Loads x', IRContains(IR, 'loadw $x'));
|
|
|
|
|
AssertTrue('Stores y', IRContains(IR, '$y'));
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{ Arithmetic }
|
|
|
|
|
|
|
|
|
|
procedure TCodeGenTests.TestAdd_EmitsAddInstruction;
|
|
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR(
|
|
|
|
|
'program P; var n: Integer; begin n := 3 + 4 end.');
|
|
|
|
|
AssertTrue('Has add', IRContains(IR, '=w add'));
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TCodeGenTests.TestMul_EmitsMulInstruction;
|
|
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR(
|
|
|
|
|
'program P; var n: Integer; begin n := 2 * 5 end.');
|
|
|
|
|
AssertTrue('Has mul', IRContains(IR, '=w mul'));
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{ Header comment }
|
|
|
|
|
|
|
|
|
|
procedure TCodeGenTests.TestOutput_HasSourceComment;
|
|
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR('program MyProg; begin end.');
|
|
|
|
|
AssertTrue('Has source comment',
|
|
|
|
|
IRContains(IR, '# Generated by Blaise Compiler'));
|
|
|
|
|
end;
|
|
|
|
|
|
2026-04-22 18:40:17 +03:00
|
|
|
{ String equality }
|
|
|
|
|
|
|
|
|
|
procedure TCodeGenTests.TestStringEq_EmitsStringEquals;
|
|
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR(
|
|
|
|
|
'program P;' + LineEnding +
|
|
|
|
|
'var S1, S2: string; B: Boolean;' + LineEnding +
|
|
|
|
|
'begin' + LineEnding +
|
|
|
|
|
' B := S1 = S2' + LineEnding +
|
|
|
|
|
'end.');
|
|
|
|
|
AssertTrue('Uses _StringEquals', IRContains(IR, '$_StringEquals'));
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TCodeGenTests.TestStringNe_EmitsStringEqualsNegated;
|
|
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR(
|
|
|
|
|
'program P;' + LineEnding +
|
|
|
|
|
'var S1, S2: string; B: Boolean;' + LineEnding +
|
|
|
|
|
'begin' + LineEnding +
|
|
|
|
|
' B := S1 <> S2' + LineEnding +
|
|
|
|
|
'end.');
|
|
|
|
|
AssertTrue('Uses _StringEquals for <>', IRContains(IR, '$_StringEquals'));
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TCodeGenTests.TestStringEq_SemanticCompiles;
|
|
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR(
|
|
|
|
|
'program P;' + LineEnding +
|
|
|
|
|
'function Same(A, B: string): Boolean;' + LineEnding +
|
|
|
|
|
'begin' + LineEnding +
|
|
|
|
|
' Result := A = B' + LineEnding +
|
|
|
|
|
'end;' + LineEnding +
|
|
|
|
|
'var B: Boolean;' + LineEnding +
|
|
|
|
|
'begin' + LineEnding +
|
|
|
|
|
' B := Same(''hello'', ''world'')' + LineEnding +
|
|
|
|
|
'end.');
|
|
|
|
|
AssertTrue('Compiles', Length(IR) > 0);
|
|
|
|
|
AssertTrue('Uses _StringEquals', IRContains(IR, '$_StringEquals'));
|
|
|
|
|
end;
|
|
|
|
|
|
2026-04-22 18:37:31 +03:00
|
|
|
{ True / False built-in constants }
|
|
|
|
|
|
|
|
|
|
procedure TCodeGenTests.TestTrue_EmitsCopyOne;
|
|
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR(
|
|
|
|
|
'program P; var B: Boolean; begin B := True end.');
|
|
|
|
|
AssertTrue('True emits copy 1', IRContains(IR, 'copy 1'));
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TCodeGenTests.TestFalse_EmitsCopyZero;
|
|
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR(
|
|
|
|
|
'program P; var B: Boolean; begin B := False end.');
|
|
|
|
|
AssertTrue('False emits copy 0', IRContains(IR, 'copy 0'));
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TCodeGenTests.TestTrue_AssignToBoolVar;
|
|
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR(
|
|
|
|
|
'program P; var B: Boolean; begin B := True end.');
|
|
|
|
|
AssertTrue('Compiles to IR', Length(IR) > 0);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TCodeGenTests.TestFalse_AssignToBoolVar;
|
|
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR(
|
|
|
|
|
'program P; var B: Boolean; begin B := False end.');
|
|
|
|
|
AssertTrue('Compiles to IR', Length(IR) > 0);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TCodeGenTests.TestTrue_InIfCondition;
|
|
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR(
|
|
|
|
|
'program P; var N: Integer; begin if True then N := 1 end.');
|
|
|
|
|
AssertTrue('Compiles to IR', Length(IR) > 0);
|
|
|
|
|
AssertTrue('Has conditional branch', IRContains(IR, 'jnz'));
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TCodeGenTests.TestBoolFunc_ReturnTrue;
|
|
|
|
|
var
|
|
|
|
|
IR: string;
|
|
|
|
|
begin
|
|
|
|
|
IR := GenerateIR(
|
|
|
|
|
'program P;' + LineEnding +
|
|
|
|
|
'function IsOK: Boolean;' + LineEnding +
|
|
|
|
|
'begin' + LineEnding +
|
|
|
|
|
' Result := True' + LineEnding +
|
|
|
|
|
'end;' + LineEnding +
|
|
|
|
|
'var B: Boolean;' + LineEnding +
|
|
|
|
|
'begin' + LineEnding +
|
|
|
|
|
' B := IsOK' + LineEnding +
|
|
|
|
|
'end.');
|
|
|
|
|
AssertTrue('IsOK function emitted', IRContains(IR, '$IsOK'));
|
|
|
|
|
AssertTrue('True emits copy 1', IRContains(IR, 'copy 1'));
|
|
|
|
|
end;
|
|
|
|
|
|
Phase 1 bootstrap: Blaise compiler skeleton
Renames the project from 'Clean Pascal' to Blaise (after Blaise Pascal).
Adds the Phase 1 compiler pipeline with TDD test suite:
- uPasTokeniser: general Pascal tokeniser (ported from fpGUI IDE)
- uLexer: compiler-specific adapter — filters whitespace/comments,
maps to TTokenKind, unescapes string literals
- uAST: typed AST node hierarchy (TProgram, TBlock, TBinaryExpr, etc.)
- uParser: recursive-descent parser for the Phase 1 BNF grammar
- uCodeGenQBE: QBE IR emitter — WriteLn/Write built-ins, integer
variables, arithmetic, string literals
- Blaise.pas: compiler driver — parses flags, shells to qbe+cc
- FPCUnit test suites for lexer, parser, and code generator
2026-04-20 17:35:50 +03:00
|
|
|
initialization
|
|
|
|
|
RegisterTest(TCodeGenTests);
|
|
|
|
|
|
|
|
|
|
end.
|