Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions tests/lit/single/literals/integer_hex_binary.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// RUN: (%COMPILE %s && %RUN) | %CHECK %s

// NOTE: The runtime monitoring write API depends on these exact values.
// If this test fails, check whether the runtime parser needs a matching update.

FUNCTION main : DINT
VAR
// Two's complement INT hex literals
i_ffff : INT := 16#FFFF;
i_8000 : INT := 16#8000;
i_7fff : INT := 16#7FFF;
i_neg_ffff : INT := -16#FFFF;
i_neg_000f : INT := -16#000F;

// Two's complement DINT hex literals
d_ffffffff : DINT := 16#FFFFFFFF;
d_80000000 : DINT := 16#80000000;

// Two's complement INT binary literal
i_bin_ffff : INT := 2#1111111111111111;
END_VAR
// --- INT hex ---
// CHECK: 16#FFFF as INT: -1
printf('16#FFFF as INT: %d$N', i_ffff);
// CHECK: 16#8000 as INT: -32768
printf('16#8000 as INT: %d$N', i_8000);
// CHECK: 16#7FFF as INT: 32767
printf('16#7FFF as INT: %d$N', i_7fff);
// CHECK: -16#FFFF as INT: 1
printf('-16#FFFF as INT: %d$N', i_neg_ffff);
// CHECK: -16#000F as INT: -15
printf('-16#000F as INT: %d$N', i_neg_000f);

// --- DINT hex ---
// CHECK: 16#FFFFFFFF as DINT: -1
printf('16#FFFFFFFF as DINT: %d$N', d_ffffffff);
// CHECK: 16#80000000 as DINT: -2147483648
printf('16#80000000 as DINT: %d$N', d_80000000);

// --- INT binary ---
// CHECK: 2#1111111111111111 as INT: -1
printf('2#1111111111111111 as INT: %d$N', i_bin_ffff);
END_FUNCTION
51 changes: 51 additions & 0 deletions tests/lit/single/string_escapes/string_escapes.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// RUN: (%COMPILE %s && %RUN) | %CHECK %s

// NOTE: The runtime monitoring write API depends on these exact values.
// If this test fails, check whether the runtime parser needs a matching update.

FUNCTION main : DINT
VAR
// 1. Valid hex escapes (ASCII range)
s_hex_hi : STRING[10] := '$48$49';

// 2. Invalid UTF-8 hex escapes (lossy replacement)
s_invalid_80 : STRING[10] := '$80';
s_caf_e9 : STRING[10] := 'caf$E9';
s_invalid_ff : STRING[10] := '$FF';
s_valid_utf8 : STRING[10] := '$F0$9F$92$96';

// 3. Named escapes
s_dollar : STRING[20] := 'Price: $$100';
s_newline : STRING[30] := 'Line1$NLine2';
s_tab : STRING[20] := 'Col1$TCol2';
s_cr : STRING[20] := 'Before$RAfter';
s_quote : STRING[20] := '$'quoted$'';
END_VAR
// --- Valid hex escapes ---
// CHECK: HI
printf('%s$N', REF(s_hex_hi));

// --- Invalid UTF-8 (lossy → U+FFFD replacement character) ---
// CHECK: �
printf('%s$N', REF(s_invalid_80));
// CHECK: caf�
printf('%s$N', REF(s_caf_e9));
// CHECK: �
printf('%s$N', REF(s_invalid_ff));
// CHECK: 💖
printf('%s$N', REF(s_valid_utf8));

// --- Named escapes ---
// Known bug: '$$' followed by 2 hex digits is double-processed in the
// committed parser (two-pass). '$$10' → '$10' (pass 1) → 0x10 DLE (pass 2).
// Remove XCHECK and restore CHECK once the single-pass fix lands.
// XCHECK: Price: $100
printf('%s$N', REF(s_dollar));
// CHECK: Line1
// CHECK: Line2
printf('%s$N', REF(s_newline));
// CHECK: Col1 Col2
printf('%s$N', REF(s_tab));
// CHECK: 'quoted'
printf('%s$N', REF(s_quote));
END_FUNCTION
13 changes: 13 additions & 0 deletions tests/lit/single/string_escapes/string_incomplete_hex.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: not %COMPILE %s
// XFAIL: *
// STRING hex escapes require exactly 2 hex digits ($hh). '$A' provides only
// one hex digit before end-of-string, which is an incomplete escape sequence
// and should be a compile error per IEC 61131-3.
// Currently the compiler silently keeps '$' and 'A' as literal characters.

FUNCTION main : DINT
VAR
s : STRING[10] := '$A';
END_VAR
main := 0;
END_FUNCTION
12 changes: 12 additions & 0 deletions tests/lit/single/string_escapes/string_invalid_escape.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: not %COMPILE %s
// XFAIL: *
// '$Q' is not a valid named escape (not $N/$R/$T/$L/$P/$$/$$') and 'Q' is not
// a hex digit, so this should be a compile error per IEC 61131-3.
// Currently the compiler silently keeps '$Q' as the two literal characters.

FUNCTION main : DINT
VAR
s : STRING[20] := 'test$Qtest';
END_VAR
main := 0;
END_FUNCTION
12 changes: 12 additions & 0 deletions tests/lit/single/string_escapes/string_trailing_dollar.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: not %COMPILE %s
// XFAIL: *
// A trailing '$' with nothing following it is an invalid escape sequence
// and should be a compile error per IEC 61131-3.
// Currently the compiler silently keeps the '$' as a literal character.

FUNCTION main : DINT
VAR
s : STRING[10] := 'hello$';
END_VAR
main := 0;
END_FUNCTION
47 changes: 47 additions & 0 deletions tests/lit/single/string_escapes/wstring_escapes.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// RUN: (%COMPILE %s && %RUN) | %CHECK %s

// NOTE: The runtime monitoring write API depends on these exact values.
// If this test fails, check whether the runtime parser needs a matching update.

FUNCTION main : DINT
VAR
// 4. WSTRING — valid hex escapes
w_hex_hi : WSTRING[10] := "$0048$0049";
w_surrogate : WSTRING[10] := "$D83D$DE00";

// 5. WSTRING — unpaired surrogate replacement
w_high_only : WSTRING[10] := "$D800";
w_low_only : WSTRING[10] := "$DE00";
w_high_not_low : WSTRING[10] := "$D83D$0041";
w_reversed : WSTRING[10] := "$DE00$D83D";

// 6. WSTRING — named escapes
w_dollar : WSTRING[20] := "Price: $$100";
w_newline : WSTRING[30] := "Line1$NLine2";
w_dquote : WSTRING[20] := "$"quoted$"";
END_VAR
// --- Valid hex escapes ---
// CHECK: HI
printf('%s$N', REF(TO_STRING(w_hex_hi)));
// CHECK: 😀
printf('%s$N', REF(TO_STRING(w_surrogate)));

// --- Unpaired surrogates (lossy → U+FFFD) ---
// CHECK: �
printf('%s$N', REF(TO_STRING(w_high_only)));
// CHECK: �
printf('%s$N', REF(TO_STRING(w_low_only)));
// CHECK: �A
printf('%s$N', REF(TO_STRING(w_high_not_low)));
// CHECK: ��
printf('%s$N', REF(TO_STRING(w_reversed)));

// --- Named escapes ---
// CHECK: Price: $100
printf('%s$N', REF(TO_STRING(w_dollar)));
// CHECK: Line1
// CHECK: Line2
printf('%s$N', REF(TO_STRING(w_newline)));
// CHECK: "quoted"
printf('%s$N', REF(TO_STRING(w_dquote)));
END_FUNCTION
13 changes: 13 additions & 0 deletions tests/lit/single/string_escapes/wstring_incomplete_hex.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: not %COMPILE %s
// XFAIL: *
// WSTRING hex escapes require exactly 4 hex digits ($hhhh). '$004' provides
// only three hex digits before end-of-string, which is an incomplete escape
// sequence and should be a compile error per IEC 61131-3.
// Currently the compiler silently keeps '$' and the remaining chars as literals.

FUNCTION main : DINT
VAR
s : WSTRING[10] := "$004";
END_VAR
main := 0;
END_FUNCTION
12 changes: 12 additions & 0 deletions tests/lit/single/string_escapes/wstring_invalid_escape.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: not %COMPILE %s
// XFAIL: *
// '$Q' is not a valid named escape and 'Q' is not a hex digit, so this should
// be a compile error per IEC 61131-3.
// Currently the compiler silently keeps '$Q' as the two literal characters.

FUNCTION main : DINT
VAR
s : WSTRING[20] := "test$Qtest";
END_VAR
main := 0;
END_FUNCTION
12 changes: 12 additions & 0 deletions tests/lit/single/string_escapes/wstring_trailing_dollar.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: not %COMPILE %s
// XFAIL: *
// A trailing '$' with nothing following it is an invalid escape sequence
// and should be a compile error per IEC 61131-3.
// Currently the compiler silently keeps the '$' as a literal character.

FUNCTION main : DINT
VAR
s : WSTRING[10] := "hello$";
END_VAR
main := 0;
END_FUNCTION
Loading