Skip to content
PaskalCPP
Language

Intrinsics

The built-in routines: lengths and sizes, wide text, printing, program arguments, memory, exceptions and weak references.

The test assertions are on Unit testing; the guard statement on guard; the exception codes and the heap report on The runtime.

Not keywords

The intrinsic names live in an outer scope of their own, not as reserved words. A declaration of yours shadows one: a routine named print, a local named len. A C function named like one is still called through its C++ name, ::size(21); where nothing shadows it, the intrinsic answers.

  • An intrinsic is always called: LN := len; is SM0423, "'len' is an intrinsic: it is called, never used as a value".
  • freemem, setlength, create, destroy, raise, raisecode, print and println are statements; used as a value they are SM0408, "'freemem' is a statement, not a value". getmem and resizemem are both expressions and statements.
  • A wrong argument is SM0409, naming what the intrinsic takes: len(5) is "'len' takes (string, wstring or array)", size() "'size' takes (a type)".
  • Each argument takes the exact type the runtime takes, with no hidden conversion: the index of paramstr and the code of raisecode are int32; the size of getmem and resizemem and the length of setlength are int64. An int64 index is SM0409, "'paramstr' takes (int32)".
  • A routine of your own that shadows size takes no type: size(int32) there is SM0411.

Length and size

  • len(x) is an int64: the bytes of a string, the wide characters of a wstring, the elements of a dynamic or static array.
  • len of a string literal counts its characters, never a terminator: len("four") is 4, len("") 0, len("a\tb") 3, and joined literals are one text.
  • size(T) is the byte size of a type, an int64 constant: a builtin, a pointer, a record, an array type or a C/C++ type. Text that is plainly a type is read as one; a lone name must name a type, so size(LN) of a variable is SM0410, "size needs a type, got the value 'LN'".
intrinsics_values.pcpp
module exe intrinsics_values;

type
  TPoint = record
    X: int32;
    Y: int32;
  end;

var
  LS: string = "hello";
  LW: wstring = L"caf\u00e9";
  LA: array of int32;
  LF: array[0..3] of int32;
  LP: ptr to int32;
  LC: ptr to const char;

begin
  setlength(LA, 3);
  println("len {} {} {} {}", len(LS), len(LW), len(LA), len(LF));
  println("literal {} {}", len("four"), len("a\tb"));
  println("size {} {} {}", size(int64), size(TPoint), size(array[0..3] of int32));
  println("utf8 {} bytes {}", utf8(LW), len(utf8(LW)));
  print("no newline, ");
  println("then one");
  println("width [{:>4}] [{:04}]", 42, 42);
  println("nil pointer {} nil text {}", LP, LC);
  LF[1] := 7;
  println("array {}", LF);
end.
output on x86_64-windows-gnu and x86_64-linux-gnu
len 5 4 3 4
literal 4 3
size 8 8 16
utf8 café bytes 5
no newline, then one
width [  42] [0042]
nil pointer 0x0 nil text nil
array [0, 7, 0, 0]
[Heap] Allocs: 0, Frees: 0, Leaked: 0

Text and printing

  • utf8(W) converts a wstring to a string in UTF-8: L"caf\u00e9" has 4 wide characters, its UTF-8 text 5 bytes.
  • print(f, ...) and println(f, ...) write std::format text, println with a newline: {:>4} right-aligns, {:04} pads with zeros. The format string is std::format's, checked when the program is built: it is a string literal or a string const holding one, more {} than arguments is SM0502, and any other format (a string variable) is SM0500.
  • Every argument prints by its PaskalCPP type: a wchar or wstring as UTF-8 text (int32(W) gives the number), a ptr to char as its text (nil prints nil), any other pointer as its address (nil prints 0x0), an array element by element, text elements quoted.
  • A record, an object or an overlay cannot be printed: SM0425, "'TP' cannot be printed: print the fields of a record, object or overlay". Neither can an overload set's name or a method (no single address), nor a C/C++ value with no formatter, reported at the argument.

Program arguments

paramcount() is the number of program arguments (int32) and paramstr(i) argument i as a string: 1-based, 0 is the program itself, "" out of range. The arguments come after -- on the pcpp command line: see The pcpp command.

Memory

  • getmem(n) gives n bytes (nil for 0), resizemem(p, n) resizes a block and keeps its bytes (from nil it allocates, to 0 it frees), freemem(p) frees it.
  • setlength(v, n) sets the length of a dynamic array or a string variable: growing adds zeroed elements, shrinking drops the tail. A negative length raises code 12, "negative length -1", and leaves the variable as it was.
  • create(p) builds a zeroed record, overlay or C/C++ value behind the pointer p; destroy(p) frees it and sets p to nil. Any other argument is SM0409, "'create' takes (record, overlay or C/C++ pointer variable)".
  • An object is never built so: create of a pointer to an object is SM0361, naming own T(...) or ref T(...), the owners that hold an object on the heap and free it (Objects).
  • The debug build's heap report counts each create as an alloc and each destroy as a free; a create never destroyed is leaked and named by its line.
intrinsics_memory.pcpp
module exe intrinsics_memory;

type
  TPoint = record
    X: int32;
    Y: int32;
  end;

var
  LP: ptr to TPoint;
  LKept: ptr to TPoint;
  LI: ptr to int32;
  LA: array of int32;

begin
  create(LP);
  println("zeroed {} {}", LP^.X, LP^.Y);
  destroy(LP);
  println("nil after destroy {}", LP = nil);
  create(LKept);
  LI := ptr to int32(getmem(16));
  LI^ := 7;
  LI := ptr to int32(resizemem(LI, 64));
  println("resized keeps {}", LI^);
  freemem(LI);
  guard
    setlength(LA, -1);
  except
    println("{} {}", exccode(), excmsg());
  end;
  guard
    raisecode(42, "answer");
  except
    println("{} {}", exccode(), excmsg());
  end;
  println("end of body");
end.
output on x86_64-windows-gnu and x86_64-linux-gnu
zeroed 0 0
nil after destroy true
resized keeps 7
12 negative length -1
42 answer
end of body
[Heap] Allocs: 3, Frees: 2, Leaked: 1
[Heap] Leaked object created at intrinsics_memory.pcpp(53)

Exceptions

  • raise(m) raises code 1 with the text m, raisecode(c, m) code c. A guard's except reads them with exccode() and excmsg(); a raise reaches the nearest guard through routine calls, and code 0 is still caught.
  • exccode() and excmsg() exist only inside an except body: anywhere else they are SM0615.
  • A raise no guard catches ends the program with "unhandled exception <code>: <text>" on stderr, after what it printed, and exit code 1: see Unhandled exceptions.

Weak references

alive(w) is true while the object a weak T watches still exists; lock(w) gives a ref T holding it, nil once it is gone. Their argument is a weak: alive of a ref is SM0409, "'alive' takes (weak T)".