diff --git a/README.md b/README.md new file mode 100644 index 0000000..2f4d6e5 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# HCL - Hybrid Command Language + +## Language Syntax + +A HCL program is composed of 0 or more expressions. + + +## Special Form Expression + +* break +* defun +* do +* elif +* else +* if +* lambda +* return +* set +* until +* while + +## literals + +* #nil +* #true +* #false diff --git a/lib/hcl.h b/lib/hcl.h index c692b66..ff6c7ea 100644 --- a/lib/hcl.h +++ b/lib/hcl.h @@ -1011,7 +1011,6 @@ struct hcl_t hcl_oop_t _else; /* symbol */ hcl_oop_t _if; /* symbol */ hcl_oop_t _lambda; /* symbol */ - hcl_oop_t _quote; /* symbol */ hcl_oop_t _return; /* symbol */ hcl_oop_t _set; /* symbol */ hcl_oop_t _until; /* symbol */ @@ -1156,28 +1155,29 @@ struct hcl_t enum hcl_log_mask_t { - HCL_LOG_DEBUG = (1 << 0), - HCL_LOG_INFO = (1 << 1), - HCL_LOG_WARN = (1 << 2), - HCL_LOG_ERROR = (1 << 3), - HCL_LOG_FATAL = (1 << 4), + HCL_LOG_DEBUG = (1 << 0), + HCL_LOG_INFO = (1 << 1), + HCL_LOG_WARN = (1 << 2), + HCL_LOG_ERROR = (1 << 3), + HCL_LOG_FATAL = (1 << 4), - HCL_LOG_UNTYPED = (1 << 6), /* only to be used by HCL_DEBUGx() and HCL_INFOx() */ - HCL_LOG_COMPILER = (1 << 7), - HCL_LOG_VM = (1 << 8), - HCL_LOG_MNEMONIC = (1 << 9), /* bytecode mnemonic */ - HCL_LOG_GC = (1 << 10), - HCL_LOG_IC = (1 << 11), /* instruction cycle, fetch-decode-execute */ - HCL_LOG_PRIMITIVE = (1 << 12), - HCL_LOG_APP = (1 << 13), /* hcl applications, set by hcl logging primitive */ + HCL_LOG_UNTYPED = (1 << 6), /* only to be used by HCL_DEBUGx() and HCL_INFOx() */ + HCL_LOG_COMPILER = (1 << 7), + HCL_LOG_VM = (1 << 8), + HCL_LOG_MNEMONIC = (1 << 9), /* bytecode mnemonic */ + HCL_LOG_GC = (1 << 10), + HCL_LOG_IC = (1 << 11), /* instruction cycle, fetch-decode-execute */ + HCL_LOG_PRIMITIVE = (1 << 12), + HCL_LOG_APP = (1 << 13), /* hcl applications, set by hcl logging primitive */ - HCL_LOG_ALL_LEVELS = (HCL_LOG_DEBUG | HCL_LOG_INFO | HCL_LOG_WARN | HCL_LOG_ERROR | HCL_LOG_FATAL), - HCL_LOG_ALL_TYPES = (HCL_LOG_UNTYPED | HCL_LOG_COMPILER | HCL_LOG_VM | HCL_LOG_MNEMONIC | HCL_LOG_GC | HCL_LOG_IC | HCL_LOG_PRIMITIVE | HCL_LOG_APP), + HCL_LOG_ALL_LEVELS = (HCL_LOG_DEBUG | HCL_LOG_INFO | HCL_LOG_WARN | HCL_LOG_ERROR | HCL_LOG_FATAL), + HCL_LOG_ALL_TYPES = (HCL_LOG_UNTYPED | HCL_LOG_COMPILER | HCL_LOG_VM | HCL_LOG_MNEMONIC | HCL_LOG_GC | HCL_LOG_IC | HCL_LOG_PRIMITIVE | HCL_LOG_APP), - HCL_LOG_STDOUT = (1 << 14), /* write log messages to stdout without timestamp. HCL_LOG_STDOUT wins over HCL_LOG_STDERR. */ - HCL_LOG_STDERR = (1 << 15) /* write log messages to stderr without timestamp. */ + HCL_LOG_STDOUT = (1 << 14), /* write log messages to stdout without timestamp. HCL_LOG_STDOUT wins over HCL_LOG_STDERR. */ + HCL_LOG_STDERR = (1 << 15), /* write log messages to stderr without timestamp. */ + HCL_LOG_PREFER_JSON = (1 << 30) /* write a object in the json format. don't set this explicitly. use %J instead */ }; typedef enum hcl_log_mask_t hcl_log_mask_t; diff --git a/lib/logfmt.c b/lib/logfmt.c index 55b20d7..3ddbe4b 100644 --- a/lib/logfmt.c +++ b/lib/logfmt.c @@ -95,7 +95,7 @@ static struct }; -enum +enum { FLAGC_DOT = (1 << 0), FLAGC_SPACE = (1 << 1), @@ -1002,6 +1002,11 @@ static HCL_INLINE int print_formatted (hcl_t* hcl, hcl_ooi_t nargs, hcl_fmtout_t if (hcl_outfmtobj(hcl, data->mask, arg, outbfmt) <= -1) goto oops; break; + case 'J': + GET_NEXT_ARG_TO (hcl, nargs, &arg_state, arg); + if (hcl_outfmtobj(hcl, data->mask | HCL_LOG_PREFER_JSON, arg, outbfmt) <= -1) goto oops; + break; + number: { const hcl_ooch_t* nsptr; diff --git a/lib/logfmtv.h b/lib/logfmtv.h index d7ac3e2..9d86ad7 100644 --- a/lib/logfmtv.h +++ b/lib/logfmtv.h @@ -588,6 +588,10 @@ static int logfmtv (hcl_t* hcl, const fmtchar_t* fmt, hcl_fmtout_t* data, va_lis if (hcl_outfmtobj(hcl, data->mask, va_arg(ap, hcl_oop_t), outbfmt) <= -1) goto oops; break; + case 'J': + if (hcl_outfmtobj(hcl, data->mask | HCL_LOG_PREFER_JSON, va_arg(ap, hcl_oop_t), outbfmt) <= -1) goto oops; + break; + #if 0 case 'e': case 'E': diff --git a/lib/print.c b/lib/print.c index 43bbffc..2075791 100644 --- a/lib/print.c +++ b/lib/print.c @@ -196,6 +196,34 @@ static HCL_INLINE int outfmt_obj (hcl_t* hcl, int mask, hcl_oop_t obj, hcl_outbf print_stack_t ps; int brand; int word_index; + int word_offset; + int json; + + static const hcl_bch_t *opening_parens[][2] = + { + { "(", "(" }, /*HCL_CONCODE_XLIST */ + { "#(", "[" }, /*HCL_CONCODE_ARRAY */ + { "#[", "[" }, /*HCL_CONCODE_BYTEARRAY */ + { "#{", "{" }, /*HCL_CONCODE_DIC */ + { "[", "]" } /*HCL_CONCODE_QLIST */ + }; + + static const hcl_bch_t *closing_parens[][2] = + { + { ")", ")" }, /*HCL_CONCODE_XLIST */ + { ")", "]" }, /*HCL_CONCODE_ARRAY */ + { "]", "]" }, /*HCL_CONCODE_BYTEARRAY */ + { "}", "}" }, /*HCL_CONCODE_DIC */ + { "]", "]" } /*HCL_CONCODE_QLIST */ + }; + + static const hcl_bch_t* breakers[][2] = + { + { " ", "," }, /* item breaker */ + { " ", ":" } /* key value breaker */ + }; + + json = !!(mask & HCL_LOG_PREFER_JSON); next: switch ((brand = HCL_BRANDOF(hcl, obj))) @@ -223,14 +251,17 @@ next: case HCL_BRAND_NIL: word_index = WORD_NIL; + word_offset = json; goto print_word; case HCL_BRAND_TRUE: word_index = WORD_TRUE; + word_offset = json; goto print_word; case HCL_BRAND_FALSE: word_index = WORD_FALSE; + word_offset = json; goto print_word; case HCL_BRAND_PBIGINT: @@ -311,28 +342,13 @@ next: case HCL_BRAND_CONS: { - static hcl_bch_t *opening_paren[] = - { - "(", /*HCL_CONCODE_XLIST */ - "#(", /*HCL_CONCODE_ARRAY */ - "#[", /*HCL_CONCODE_BYTEARRAY */ - "#{", /*HCL_CONCODE_DIC */ - "[" /*HCL_CONCODE_QLIST */ - }; - - static hcl_bch_t *closing_paren[] = - { - ")", /*HCL_CONCODE_XLIST */ - ")", /*HCL_CONCODE_ARRAY */ - "]", /*HCL_CONCODE_BYTEARRAY */ - "}", /*HCL_CONCODE_DIC */ - "]" /*HCL_CONCODE_QLIST */ - }; - int concode; + /* this part is to print a linked list of cells. ignore the + * request to output in the json format */ + concode = HCL_OBJ_GET_FLAGS_SYNCODE(obj); - if (outbfmt(hcl, mask, opening_paren[concode]) <= -1) return -1; + if (outbfmt(hcl, mask, opening_parens[concode][0]) <= -1) return -1; cur = obj; do @@ -384,11 +400,11 @@ next: } /* The CDR part points to a pair. proceed to it */ - if (outbfmt(hcl, mask, " ") <= -1) return -1; + if (outbfmt(hcl, mask, breakers[0][0]) <= -1) return -1; } while (1); - if (outbfmt(hcl, mask, closing_paren[concode]) <= -1) return -1; + if (outbfmt(hcl, mask, closing_parens[concode][0]) <= -1) return -1; break; } @@ -396,11 +412,11 @@ next: { hcl_oow_t arridx; - if (outbfmt(hcl, mask, "#(") <= -1) return -1; + if (outbfmt(hcl, mask, opening_parens[HCL_CONCODE_ARRAY][json]) <= -1) return -1; if (HCL_OBJ_GET_SIZE(obj) <= 0) { - if (outbfmt(hcl, mask, ")") <= -1) return -1; + if (outbfmt(hcl, mask, closing_parens[HCL_CONCODE_ARRAY][json]) <= -1) return -1; break; } arridx = 0; @@ -428,7 +444,7 @@ next: obj = ((hcl_oop_oop_t)obj)->slot[arridx]; if (arridx > 0) { - if (outbfmt(hcl, mask, " ") <= -1) return -1; + if (outbfmt(hcl, mask, breakers[0][json]) <= -1) return -1; } /* Jump to the 'next' label so that the object * pointed to by 'obj' is printed. Once it @@ -448,14 +464,16 @@ next: case HCL_BRAND_BYTE_ARRAY: { hcl_oow_t i; - - if (outbfmt(hcl, mask, "#[") <= -1) return -1; - - for (i = 0; i < HCL_OBJ_GET_SIZE(obj); i++) + if (outbfmt(hcl, mask, opening_parens[HCL_CONCODE_BYTEARRAY][json]) <= -1) return -1; + if (HCL_OBJ_GET_SIZE(obj) > 0) { - if (outbfmt(hcl, mask, "%hs%d", ((i > 0)? " ": ""), ((hcl_oop_byte_t)obj)->slot[i]) <= -1) return -1; + if (outbfmt(hcl, mask, "%d", ((hcl_oop_byte_t)obj)->slot[0]) <= -1) return -1; + for (i = 1; i < HCL_OBJ_GET_SIZE(obj); i++) + { + if (outbfmt(hcl, mask, "%hs%d", breakers[0][json], ((hcl_oop_byte_t)obj)->slot[i]) <= -1) return -1; + } } - if (outbfmt(hcl, mask, "]") <= -1) return -1; + if (outbfmt(hcl, mask, closing_parens[HCL_CONCODE_BYTEARRAY][json]) <= -1) return -1; break; } @@ -464,13 +482,13 @@ next: hcl_oow_t bucidx, bucsize, buctally; hcl_oop_dic_t dic; - if (outbfmt(hcl, mask, "#{") <= -1) return -1; + if (outbfmt(hcl, mask, opening_parens[HCL_CONCODE_DIC][json]) <= -1) return -1; dic = (hcl_oop_dic_t)obj; HCL_ASSERT (hcl, HCL_OOP_IS_SMOOI(dic->tally)); if (HCL_OOP_TO_SMOOI(dic->tally) <= 0) { - if (outbfmt(hcl, mask, "}") <= -1) return -1; + if (outbfmt(hcl, mask, closing_parens[HCL_CONCODE_DIC][json]) <= -1) return -1; break; } bucidx = 0; @@ -496,7 +514,7 @@ next: if (bucidx >= bucsize) { /* done. scanned the entire bucket */ - if (outbfmt(hcl, mask, "}") <= -1) return -1; + if (outbfmt(hcl, mask, closing_parens[HCL_CONCODE_DIC][json]) <= -1) return -1; break; } @@ -537,7 +555,7 @@ next: if (buctally > 0) { - if (outbfmt(hcl, mask, " ") <= -1) return -1; + if (outbfmt(hcl, mask, breakers[buctally & 1][json]) <= -1) return -1; } /* Jump to the 'next' label so that the object @@ -606,7 +624,7 @@ next: return -1; print_word: - if (outbfmt(hcl, mask, "%.*js", word[word_index].len, word[word_index].ptr) <= -1) return -1; + if (outbfmt(hcl, mask, "%.*js", word[word_index].len - word_offset, word[word_index].ptr + word_offset) <= -1) return -1; break; }