<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharlie Stanton <charlie@shtanton.xyz>2022-01-09 15:10:21 +0000
committerCharlie Stanton <charlie@shtanton.xyz>2022-01-09 15:10:21 +0000
commite5d44899cffd80653da9e0336af36230c4e992a0 (patch)
tree07587e6b88b5d7d5c41f222a567a7b783fa35c80
parentfbcba2f689348fb723f8d33f3d8e2010e4864e85 (diff)
downloadcudl-main.tar
Add parsing numbersHEADmain
-rw-r--r--cudl.c69
-rw-r--r--cudl.h1
-rw-r--r--test.cudl5
3 files changed, 73 insertions, 2 deletions
diff --git a/cudl.c b/cudl.c
index b596e92..b5022a7 100644
--- a/cudl.c
+++ b/cudl.c
@@ -5,6 +5,7 @@
#include "cudl.h"
#define STRIP_WHITESPACE(text) while (isspace(*(text))) (text)++
+
#define IS_KEY_CHAR(c) (\
'a' <= (c) && (c) <= 'z' ||\
'A' <= (c) && (c) <= 'Z' ||\
@@ -12,6 +13,10 @@
(c) == '_' || (c) == '-'\
)
+#define IS_DIGIT(c) (\
+ '0' <= (c) && (c) <= '9'\
+)
+
int cudl_err = CUDL_OK;
static char *fread_all(FILE *file) {
@@ -43,18 +48,26 @@ void cudl_debug(struct cudl_value value) {
else
printf("%%false");
break;
+ case CUDL_TAG_NUMBER:
+ printf("%lf", value.data.number);
+ break;
case CUDL_TAG_STRING:
printf("\"%s\"", value.data.string);
break;;
case CUDL_TAG_ARRAY:
printf("[");
- for (i = 0; i < value.data.array.length; i++)
+ for (i = 0; i < value.data.array.length; i++) {
+ if (i != 0)
+ printf(" ");
cudl_debug(value.data.array.values[i]);
+ }
printf("]");
break;
case CUDL_TAG_MAP:
printf("{");
for (i = 0; i < value.data.map.length; i++) {
+ if (i != 0)
+ printf(" ");
printf("\"%s\": ", value.data.map.fields[i].key);
cudl_debug(value.data.map.fields[i].value);
}
@@ -106,11 +119,61 @@ static size_t parse_bool_or_null(char *input, struct cudl_value *value) {
return 0;
}
+static size_t parse_number(char *input, struct cudl_value *value) {
+ double number;
+ size_t i, exponentStart;
+ int exponent, otherExponent;
+ int exponentUsed;
+ exponentUsed = 0;
+ number = 0;
+ i = input[0] == '-';
+ for (;; i++) {
+ if (IS_DIGIT(input[i])) {
+ number = number * 10 + (input[i] - '0');
+ exponent++;
+ continue;
+ } else if (input[i] == '.') {
+ exponent = 0;
+ exponentUsed = 1;
+ continue;
+ }
+ break;
+ }
+ if (input[0] == '-')
+ number = 0 - number;
+ if (!exponentUsed)
+ exponent = 0;
+ otherExponent = 0;
+ if (input[i] == 'e' && (IS_DIGIT(input[i+1]) || (input[i+1] == '-' && IS_DIGIT(input[i+2])))) {
+ i++;
+ exponentStart = i;
+ i += input[i] == '-';
+ for (;; i++) {
+ if (IS_DIGIT(input[i]))
+ otherExponent = otherExponent * 10 + (input[i] - '0');
+ else
+ break;
+ }
+ if (input[exponentStart] == '-')
+ otherExponent = 0 - otherExponent;
+ }
+ exponent = exponent - otherExponent;
+ for (; exponent > 0; exponent--) {
+ number /= 10;
+ }
+ for (; exponent < 0; exponent++) {
+ number *= 10;
+ }
+ value->tag = CUDL_TAG_NUMBER;
+ value->data.number = number;
+ return i;
+}
+
/* Convert UCS character to utf-8 bytes.
* Return number of bytes generated.
* Sets cudl_error on error.
* Shamelessly lifted from https://github.com/cktan/tomc99 */
-size_t cudl_ucs_to_utf8(int64_t ucs, char utf8[6]) {
+static size_t cudl_ucs_to_utf8(int64_t ucs, char utf8[6]) {
if (
0xd800 <= ucs && ucs <= 0xdfff ||
0xfffe <= ucs && ucs <= 0xffff ||
@@ -482,6 +545,8 @@ static size_t _parse_value(char *input, struct cudl_value *value) {
value->tag = CUDL_TAG_STRING;
return parse_quoted_string(++input, &value->data.string) + 1;
}
+ if (IS_DIGIT(*input) || *input == '-')
+ return parse_number(input, value);
cudl_err = CUDL_ERR_UNRECOGNISED_VALUE;
return 0;
}
diff --git a/cudl.h b/cudl.h
index 36d2365..6f78909 100644
--- a/cudl.h
+++ b/cudl.h
@@ -33,6 +33,7 @@ struct cudl_map_field {
enum {
CUDL_TAG_NULL,
CUDL_TAG_BOOL,
+ CUDL_TAG_NUMBER,
CUDL_TAG_ARRAY,
CUDL_TAG_MAP,
CUDL_TAG_STRING,
diff --git a/test.cudl b/test.cudl
index a9de397..b95e6be 100644
--- a/test.cudl
+++ b/test.cudl
@@ -4,6 +4,11 @@
[%null %null %false]
["hello\nfriend\t\tstuff\"" "world"]
"\U0001f600"
+ 12
+ 12.4
+ 13.456
+ 123.345e4
+ 123456789e-8
{
testing: "this is a test map"
i_hope_it_works: {nesting: "nested maps!!!"}