picofuse

rune.h
Go to the documentation of this file.
1 
17 #pragma once
18 #include <picofuse/sys.h>
19 #include <stdbool.h>
20 #include <stddef.h>
21 #include <stdint.h>
22 
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26 
28 typedef int32_t rune_t;
29 
39 #define RUNE_ERROR ((rune_t)0xFFFD)
40 
52 extern const char *sys_rune_next(const char *str, rune_t *rune);
53 
62 extern size_t sys_rune_count(const char *str);
63 
72 extern bool sys_rune_valid(const char *str);
73 
75 // CLASSIFICATION
76 //
77 // These classify ASCII plus the Latin-1 Supplement block (0x80-0xFF) -
78 // accented Western European letters and their punctuation/space/control
79 // characters are recognized, but every other script (Greek, Cyrillic, CJK,
80 // etc.) is out of scope and reports false from all of them.
81 
86 static inline bool sys_rune_is_digit(rune_t r) { return r >= '0' && r <= '9'; }
87 
93 static inline bool sys_rune_is_space(rune_t r) {
94  switch (r) {
95  case ' ':
96  case '\t':
97  case '\n':
98  case '\v':
99  case '\f':
100  case '\r':
101  case 0x0085: // NEL
102  case 0x00A0: // NBSP
103  return true;
104  default:
105  return false;
106  }
107 }
108 
113 static inline bool sys_rune_is_upper(rune_t r) {
114  if (r >= 'A' && r <= 'Z') {
115  return true;
116  }
117  if (r >= 0x00C0 && r <= 0x00D6) { // A grave - O diaeresis
118  return true;
119  }
120  if (r >= 0x00D8 && r <= 0x00DE) { // O stroke - Thorn
121  return true;
122  }
123  return false;
124 }
125 
130 static inline bool sys_rune_is_lower(rune_t r) {
131  if (r >= 'a' && r <= 'z') {
132  return true;
133  }
134  if (r == 0x00DF) { // sharp s
135  return true;
136  }
137  if (r >= 0x00E0 && r <= 0x00F6) { // a grave - o diaeresis
138  return true;
139  }
140  if (r >= 0x00F8 && r <= 0x00FF) { // o stroke - y diaeresis
141  return true;
142  }
143  return false;
144 }
145 
150 static inline bool sys_rune_is_alpha(rune_t r) {
151  return sys_rune_is_upper(r) || sys_rune_is_lower(r);
152 }
153 
162 static inline rune_t sys_rune_to_upper(rune_t r) {
163  if (r >= 'a' && r <= 'z') {
164  return r - 32;
165  }
166  if (r >= 0x00E0 && r <= 0x00F6) { // a grave - o diaeresis
167  return r - 0x20;
168  }
169  if (r >= 0x00F8 && r <= 0x00FE) { // o stroke - thorn
170  return r - 0x20;
171  }
172  return r;
173 }
174 
181 static inline rune_t sys_rune_to_lower(rune_t r) {
182  if (r >= 'A' && r <= 'Z') {
183  return r + 32;
184  }
185  if (r >= 0x00C0 && r <= 0x00D6) { // A grave - O diaeresis
186  return r + 0x20;
187  }
188  if (r >= 0x00D8 && r <= 0x00DE) { // O stroke - Thorn
189  return r + 0x20;
190  }
191  return r;
192 }
193 
202 static inline bool sys_rune_is_punct(rune_t r) {
203  switch (r) {
204  case '!':
205  case '"':
206  case '#':
207  case '%':
208  case '&':
209  case '\'':
210  case '(':
211  case ')':
212  case '*':
213  case ',':
214  case '-':
215  case '.':
216  case '/':
217  case ':':
218  case ';':
219  case '?':
220  case '@':
221  case '[':
222  case '\\':
223  case ']':
224  case '_':
225  case '{':
226  case '}':
227  case 0x00A1: // inverted exclamation mark
228  case 0x00A7: // section sign
229  case 0x00B6: // pilcrow sign
230  case 0x00B7: // middle dot
231  case 0x00BF: // inverted question mark
232  return true;
233  default:
234  return false;
235  }
236 }
237 
246 static inline bool sys_rune_is_symbol(rune_t r) {
247  switch (r) {
248  case '$':
249  case '+':
250  case '<':
251  case '=':
252  case '>':
253  case '^':
254  case '`':
255  case '|':
256  case '~':
257  case 0x00A2: // cent sign
258  case 0x00A3: // pound sign
259  case 0x00A4: // currency sign
260  case 0x00A5: // yen sign
261  case 0x00A6: // broken bar
262  case 0x00A8: // diaeresis
263  case 0x00A9: // copyright sign
264  case 0x00AC: // not sign
265  case 0x00AE: // registered sign
266  case 0x00AF: // macron
267  case 0x00B0: // degree sign
268  case 0x00B1: // plus-minus sign
269  case 0x00B4: // acute accent
270  case 0x00B8: // cedilla
271  case 0x00D7: // multiplication sign
272  case 0x00F7: // division sign
273  return true;
274  default:
275  return false;
276  }
277 }
278 
283 static inline bool sys_rune_is_control(rune_t r) {
284  if (r >= 0x00 && r <= 0x1F) {
285  return true;
286  }
287  if (r == 0x7F) { // DEL
288  return true;
289  }
290  if (r >= 0x80 && r <= 0x9F) { // C1 controls
291  return true;
292  }
293  return false;
294 }
295 
297 // TOKENIZATION
298 
303 typedef enum {
312 
323 extern sys_rune_class_t sys_rune_isa(rune_t r);
324 
336 typedef struct sys_rune_tokenize_t {
338  ptrdiff_t start;
339  size_t bytes;
340  size_t runes;
341  sys_rune_class_t isa;
343 
351 
360 
371 extern size_t sys_rune_tokenize_token(sys_rune_tokenize_t *it, char *buf,
372  size_t cap);
373 
375 
376 #ifdef __cplusplus
377 }
378 #endif
sys_iostream_t * stream
source (private)
Definition: rune.h:337
see sys_rune_is_symbol()
Definition: rune.h:309
Tokenizer state, grouping a stream into maximal runs of same-class runes.
Definition: rune.h:336
int32_t rune_t
A single decoded Unicode code point.
Definition: rune.h:28
see sys_rune_is_digit()
Definition: rune.h:306
static bool sys_rune_is_symbol(rune_t r)
Reports whether r is a symbol character (math, currency, or modifier symbols).
Definition: rune.h:246
static bool sys_rune_is_punct(rune_t r)
Reports whether r is a punctuation character.
Definition: rune.h:202
size_t bytes
length of the current token, in bytes
Definition: rune.h:339
static bool sys_rune_is_space(rune_t r)
Reports whether r is a space character (space, \t, \n, \v, \f, \r, U+0085 NEL, or U+00A0 NBSP)...
Definition: rune.h:93
static bool sys_rune_is_alpha(rune_t r)
Reports whether r is a letter.
Definition: rune.h:150
unclassified - also covers RUNE_ERROR
Definition: rune.h:304
size_t sys_rune_tokenize_token(sys_rune_tokenize_t *it, char *buf, size_t cap)
Read the current token&#39;s text.
System abstraction headers and process lifecycle hooks.
see sys_rune_is_alpha()
Definition: rune.h:307
bool sys_rune_valid(const char *str)
Check whether a string is well-formed UTF-8.
struct sys_iostream_t sys_iostream_t
An opaque byte stream.
Definition: io.h:68
static bool sys_rune_is_lower(rune_t r)
Reports whether r is a lowercase letter.
Definition: rune.h:130
static bool sys_rune_is_control(rune_t r)
Reports whether r is a control character.
Definition: rune.h:283
sys_rune_class_t
Classification of a rune, or of a maximal run of same-class runes.
Definition: rune.h:303
size_t runes
number of runes in the current token
Definition: rune.h:340
static bool sys_rune_is_upper(rune_t r)
Reports whether r is an uppercase letter.
Definition: rune.h:113
bool sys_rune_tokenize_next(sys_rune_tokenize_t *it)
Advance to the next maximal run of same-class runes.
see sys_rune_is_control()
Definition: rune.h:310
size_t sys_rune_count(const char *str)
Count the runes in a UTF-8 string.
struct sys_rune_tokenize_t sys_rune_tokenize_t
Tokenizer state, grouping a stream into maximal runs of same-class runes.
sys_rune_class_t isa
classification shared by the whole token
Definition: rune.h:341
const char * sys_rune_next(const char *str, rune_t *rune)
Decode the next UTF-8 rune from a string.
static bool sys_rune_is_digit(rune_t r)
Reports whether r is a decimal digit.
Definition: rune.h:86
see sys_rune_is_space()
Definition: rune.h:305
static rune_t sys_rune_to_lower(rune_t r)
Converts r to its lowercase form, if it has one.
Definition: rune.h:181
ptrdiff_t start
absolute stream position where the current token begins
Definition: rune.h:338
see sys_rune_is_punct()
Definition: rune.h:308
sys_rune_tokenize_t sys_rune_tokenize_init(sys_iostream_t *stream)
Initialize a tokenizer over a stream.
static rune_t sys_rune_to_upper(rune_t r)
Converts r to its uppercase form, if it has one.
Definition: rune.h:162
sys_rune_class_t sys_rune_isa(rune_t r)
Classify a single rune.