Declarations
Constants, variables, routines, forward declarations, exported names, linkage, overloads and variadic routines. Types themselves are on Types and Objects.
module exe declarations;
// A const always names its type; a const can bound an array
const
CCount: int32 = 3;
var
GSlots: array[0..CCount - 1] of int32;
GTotal: int32 = 10;
GZero: int32;
GName: string = "PaskalCPP";
// IsOdd is called before its full declaration: forward makes it visible
forward routine IsOdd(AN: int32): bool;
routine IsEven(AN: int32): bool;
begin
if AN = 0 then
return true;
end;
return IsOdd(AN - 1);
end;
routine IsOdd(AN: int32): bool;
begin
if AN = 0 then
return false;
end;
return IsEven(AN - 1);
end;
// var: the caller's variable itself; const: read only
routine Bump(var AN: int32);
begin
AN := AN + 1;
end;
routine Twice(const AN: int32): int32;
begin
return AN * 2;
end;
// Overloads differ in their parameter types
routine Kind(AN: int32): string;
begin
return "int32";
end;
routine Kind(AS: string): string;
begin
return "string";
end;
routine Kind(AB: bool): string;
begin
return "bool";
end;
// A trailing ... makes a routine variadic; varargs reads the extra arguments
routine Total(ABase: int32; ...): int64;
var
LT: int64;
LI: int32;
begin
LT := ABase;
LI := 0;
while LI < varargs.count do
LT := LT + varargs.get(LI, int32);
LI := LI + 1;
end;
return LT;
end;
begin
println("CCount = {}, len(GSlots) = {}", CCount, len(GSlots));
println("GTotal = {}, GZero = {}, GName = {}", GTotal, GZero, GName);
println("IsEven(10) = {}, IsOdd(7) = {}", IsEven(10), IsOdd(7));
Bump(GTotal);
println("Bump: {}", GTotal);
println("Twice(21) = {}", Twice(21));
println("Kind(5) = {}, Kind(\"x\") = {}, Kind(true) = {}", Kind(5), Kind("x"), Kind(true));
println("Total(100, 1, 2, 3) = {}", Total(100, 1, 2, 3));
// A body var is visible from its own line on
var LInner: int32 = GTotal * 2;
println("LInner = {}", LInner);
end.
CCount = 3, len(GSlots) = 3
GTotal = 10, GZero = 0, GName = PaskalCPP
IsEven(10) = true, IsOdd(7) = true
Bump: 11
Twice(21) = 42
Kind(5) = int32, Kind("x") = string, Kind(true) = bool
Total(100, 1, 2, 3) = 106
LInner = 22
[Heap] Allocs: 0, Frees: 0, Leaked: 0
Declare before use
Everything is explicit: a name is visible only after its declaration, at every level (module, routine, body, nested block). A variable, type or routine used before it is SM0002; a variable named in its own initializer is SM0001. A routine is visible in its own body, so recursion needs no forward declaration.
- Two declarations of one name in one scope are SM0004: two module variables, two parameters, a routine's variable named like its parameter, a variable and a routine.
- A declaration in an inner scope shadows an outer one of the same name: a routine's variable hides a module variable, a variable in an
ifblock hides the routine's. The outer one is unchanged. - Names starting with
pcpp_belong to the compiler: a module, const, type, field, choice value, variable, routine, parameter or local named so is SM0017. The rule is case-sensitive (Pcpp_Gis free); a name in mixed C++ is clang's to judge.
Constants
const Name: Type = value; always names its type; no type is inferred from the value, and a const with no type is PR0001.
- A const value is a constant: a literal (a string too), an earlier const, an operator over constants, or opaque C++ such as
INT_MAX, which clang judges. A variable or a routine call is SM0202. - The value converts to the declared type only when no value can be lost: a constant that does not fit (300 into int8, -1 into uint8) or a float for an integer const is SM0200.
- A const stands wherever a constant is required, such as an array bound. Const blocks may stand at module level, in a routine before its
begin, and as a statement in a body.
Variables
var Name: Type [= value]; declares a variable. The initializer is any expression of names declared before it, converted only when no value can be lost: an int32 into an int8 is SM0200.
- A variable without an initializer starts as its type's zero: 0, false, an empty string, every record field and array element zero, nil for a pointer.
- A routine's locals start over on every call; a module variable keeps its value.
- A
varstatement in a body declares a variable visible from its own line on. Name: Type; external;binds the C symbol of that name: at module level only (SM0302 in a routine or the main block), with no initializer (SM0301).
Routines
routine Name[(params)][: Type]; then a body. With a return type it is a function and returns with return <value>; without one it is a procedure, called as a statement. The parameter list may be left out entirely; a call still writes ().
A parameter is passed by value (a copy), var (the caller's variable itself) or const (read only); parameters are separated by ;.
- A
varargument must be a variable of exactly the parameter's type: a literal or an int64 for avarint32 is SM0405. A constant argument that does not fit a value parameter is SM0404. - A procedure call used as a value is SM0406;
return;in a function is SM0610; a function that can reach its end without returning is SM0612 at itsend. - A routine body holds any number of
type,constandvarblocks, in any order, before itsbegin; a method body takes onlyvarblocks (a const block there is PR0025).
External routines
external replaces a routine's body and binds a symbol linked from elsewhere; with no library the symbol is in this build, for example a C file added with @addsourcefile.
external "lib"; or external CName; (a const string) names the library to link, as @linklibrary does; the program then needs no @linklibrary. A file name there is PR0055, a const that is not a string or a name nothing declares SM0326, a const naming a path SM0327; a library the linker cannot find is reported at the clause's library name.
Linkage
cpplink (C++ linkage, a mangled name) is the default. clink gives a routine C linkage (extern "C", its plain name), so C code can call it by name, and PaskalCPP can bind a C routine with clink and external.
module dll linkage_clink;
exported routine clink AddInts(const AA: int32; const AB: int32): int32;
begin
return AA + AB;
end;
end.
C has no overloads: an overloaded clink routine gets C++ linkage, with the warning SM0323 on each one, and the build succeeds.
Forward declarations
forward routine ...; and forward type Name; make a name visible before its full declaration, for mutual recursion and self-referencing types.
- The full routine must follow in the same scope and match the forward exactly: linkage, exported or not, variadic, parameter names, modes and return type each differ as SM0306. A forward routine never declared in full is SM0307; a full routine with other parameter types pairs with no forward (it is a new overload) and leaves the forward SM0307.
- A forward type is completed by a
record,objectoroverlay(an alias is SM0305). Until then it is used only behindptr to(by value it is SM0300) or inside a routine type's parameter and return types. Never completed is SM0303, a forward after the full declaration SM0304.
exported
exported before a module-level declaration makes it visible to importing modules, reached as unit.Name, or bare when only one imported unit exports the name (see Modules); without it a declaration is private to its module. It covers the one declaration after it, a whole var, const or type block included, and nothing after that block.
- A private name used by an importer is SM0006, including a private constant the unit's exported declarations are built from.
- Exported declarations may be built from the unit's private constants and types (an array bound, an
alignvalue, a parameter type); the importer uses them all. exportedis module level only (PR0057 among a routine's own declarations) and precedes a PaskalCPP declaration only: before C++,cpp header;, the main block or a secondexportedit is PR0024. A main module may export too.
Overloads
Routines of one name in one scope are overloads when their parameter types differ, in count or in a type. Parameter names, var / const, linkage and the return type make no overload: a repeat is SM0324 at the later one.
A call considers only the overloads that take its arguments by PaskalCPP's implicit conversions (a C/C++ value is taken by every one); none is SM0402, naming them all. Among those that take them, C++'s ranking picks: Kind("text") with a bool and a string overload calls the string one, and an int64 never narrows to an int32 overload.
- A forward and its full declaration are one overload.
- An imported unit's overloads never join the module's own set of that name: a bare call sees the module's own set (SM0404 when none of it takes the arguments), the unit's is reached qualified. One imported unit's set, with no own name of that spelling, is used bare as that set.
Variadic routines
A trailing ... (after ;) makes a routine variadic; varargs reads the extra arguments. varargs in a routine that is not variadic is SM0417.
- cpplink (the default): every argument travels with its type.
varargs.count,next(T),get(i, T),reset()andcopy()are available (avarargslocal holds an independent copy, cursor included), and no fixed parameter is needed. Integer literals pack as int32 (int64 when larger), float literals as float64, string literals as string. A cpplink variadic routine cannot share its name with another routine (SM0330). - clink: the C calling convention, so only
varargs.next(varargs.countis SM0418: pass the count yourself), and a routine with a body needs a fixed parameter before...(SM0325). An external clink routine may be declared with...alone.