├── dis ├── dis.h └── dis.c ├── README.md ├── mu ├── sys.h ├── types.c ├── config.h ├── parse.h ├── vm.h ├── num.h ├── str.h ├── types.h ├── fn.h ├── tbl.h ├── fn.c ├── buf.h ├── buf.c ├── vm.c ├── mu.h ├── str.c ├── num.c └── tbl.c ├── LICENSE.md ├── Makefile ├── repl ├── repl.h └── repl.c └── main.c /dis/dis.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu disassembly library for debugging 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #ifndef MU_DIS_H 8 | #define MU_DIS_H 9 | #include "mu/mu.h" 10 | 11 | 12 | // Disassemble bytecode for debugging and introspection, outputs to stdout 13 | // Does not consume its argument to help when debugging 14 | void mu_dis(mu_t mu); 15 | 16 | // Disassembler module in Mu 17 | #define MU_DIS_KEY mu_dis_key_def() 18 | #define MU_DIS mu_dis_def() 19 | #define MU_DIS_MODULE mu_dis_module_def() 20 | MU_DEF(mu_dis_key_def) 21 | MU_DEF(mu_dis_def) 22 | MU_DEF(mu_dis_module_def) 23 | 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Mu is a lightweight scripting language designed to be easily embeddable. 2 | With simplicity as its core goal, Mu boasts a minimal language backed by a 3 | small, but powerful, builtin library. 4 | 5 | ``` sh 6 | # A quicksort implementation 7 | fn qsort(data) 8 | let [x, ..data] = tbl(data) 9 | if (len(data) == 0) 10 | return [x] 11 | 12 | let small = filter(fn(y) -> y < x, data) 13 | let large = filter(fn(y) -> y >= x, data) 14 | return qsort(small) ++ [x] ++ qsort(large) 15 | ``` 16 | 17 | You can find out more about the language [here](http://mu-script.org/) 18 | -------------------------------------------------------------------------------- /mu/sys.h: -------------------------------------------------------------------------------- 1 | /* 2 | * System dependent hooks for Mu 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #ifndef MU_SYS_H 8 | #define MU_SYS_H 9 | #include "config.h" 10 | #include "types.h" 11 | 12 | 13 | // It's up to the system using Mu to provide the following functions 14 | 15 | // Called when an error occurs, it's up to the system what to do, 16 | // but this function can not return. 17 | mu_noreturn mu_sys_error(const char *message, muint_t len); 18 | 19 | // Called by Mu's print function. Intended for debugging purposes. 20 | void mu_sys_print(const char *message, muint_t len); 21 | 22 | // Called by Mu to import a module if it can't be found in the 23 | // currently loaded modules. 24 | mu_t mu_sys_import(mu_t name); 25 | 26 | 27 | // These can be defined but are only used if MU_MALLOC is undefined 28 | 29 | // Allocate memory 30 | // Must garuntee 8-byte alignment 31 | void *mu_sys_alloc(muint_t size); 32 | 33 | // Deallocate memory 34 | // Must not error on 0 35 | void mu_sys_dealloc(void *m, muint_t size); 36 | 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Christopher Haster 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a 4 | copy of this software and associated documentation files (the "Software"), 5 | to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the 8 | Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET = bin/mu 2 | BIN = bin 3 | BUILD = build 4 | 5 | 6 | CC = gcc 7 | SIZE = size 8 | 9 | DIR += . mu repl 10 | SRC += $(foreach dir,$(DIR),$(wildcard $(dir)/*.c)) 11 | OBJ += $(SRC:%.c=$(BUILD)/%.o) 12 | DEP += $(SRC:%.c=$(BUILD)/%.d) 13 | ASM += $(SRC:%.c=$(BUILD)/%.s) 14 | 15 | ifdef DEBUG 16 | CFLAGS += -O0 -g3 -DMU_DEBUG 17 | CFLAGS += -fkeep-inline-functions 18 | else ifdef FAST 19 | CFLAGS += -O3 -DMU_FAST 20 | else # default to SMALL 21 | CFLAGS += -Os -DMU_SMALL 22 | endif 23 | CFLAGS += -I. 24 | CFLAGS += -std=c99 -pedantic 25 | CFLAGS += -Wall -Winline 26 | 27 | LFLAGS += -lm 28 | 29 | ifdef MU_NO_DIS 30 | CFLAGS += -DMU_NO_DIS 31 | else 32 | DIR += dis 33 | endif 34 | 35 | 36 | all: $(TARGET) 37 | 38 | asm: $(ASM) 39 | 40 | size: $(OBJ) 41 | $(SIZE) -t $^ 42 | 43 | -include $(DEP) 44 | 45 | $(TARGET): $(OBJ) 46 | $(CC) $(CFLAGS) $^ $(LFLAGS) -o $@ 47 | 48 | $(BUILD): 49 | mkdir -p $(BIN) $(addprefix $(BUILD)/,$(DIR)) 50 | 51 | $(BUILD)/%.o: %.c | $(BUILD) 52 | $(CC) -c -MMD $(CFLAGS) $< -o $@ 53 | 54 | $(BUILD)/%.s: %.c | $(BUILD) 55 | $(CC) -S $(CFLAGS) $< -o $@ 56 | 57 | clean: 58 | rm -rf $(BIN) $(BUILD) 59 | -------------------------------------------------------------------------------- /repl/repl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu repl library for presenting a user-interactive interface 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #ifndef MU_REPL_H 8 | #define MU_REPL_H 9 | #include "mu/mu.h" 10 | 11 | 12 | // Length of history to remember in interactive session, history is currently 13 | // shared globally 14 | #ifndef MU_REPL_HISTORY 15 | #define MU_REPL_HISTORY 100 16 | #endif 17 | 18 | 19 | // By default, Mu will make system calls to read/write to stdin/stdout. 20 | // If set to zero, the term sys functions must be defined. 21 | #ifndef MU_USE_STD_TERM 22 | #define MU_USE_STD_TERM 1 23 | #endif 24 | 25 | // Sys functions that must be defined if MU_USE_STD_TERM is 0 26 | int mu_sys_termenter(void); 27 | void mu_sys_termexit(void); 28 | 29 | mint_t mu_sys_termread(void *buf, muint_t n); 30 | mint_t mu_sys_termwrite(const void *buf, muint_t n); 31 | 32 | 33 | // Read data interactively from user, returned as a raw string in a mu buf. 34 | // The scope is used for mu-style tab completion or may be nil to disable. 35 | mu_t mu_repl_read(const char *prompt, mu_t scope); 36 | 37 | // Eval user input as a mu statement 38 | void mu_repl_feval(const char *prompt, mu_t scope, mcnt_t fc, mu_t *frame); 39 | mu_t mu_repl_veval(const char *prompt, mu_t scope, mcnt_t fc, va_list args); 40 | mu_t mu_repl_eval(const char *prompt, mu_t scope, mcnt_t fc, ...); 41 | 42 | // Eval user input and print the results to the user. This is best for a 43 | // fully interactive session, and the scope can still be used for side effects 44 | void mu_repl(const char *prompt, mu_t scope); 45 | 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /mu/types.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Type definitions for Mu 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #include "types.h" 8 | #include "mu.h" 9 | 10 | 11 | // Mu type destruction 12 | void mu_destroy(mu_t m) { 13 | extern void mu_str_destroy(mu_t); 14 | extern void mu_buf_destroy(mu_t); 15 | extern void mu_buf_destroydtor(mu_t); 16 | extern void mu_tbl_destroy(mu_t); 17 | extern void mu_fn_destroy(mu_t); 18 | 19 | switch (mu_gettype(m)) { 20 | case MTSTR: mu_str_destroy(m); return; 21 | case MTBUF: mu_buf_destroy(m); return; 22 | case MTDBUF: mu_buf_destroydtor(m); return; 23 | case MTTBL: mu_tbl_destroy(m); return; 24 | case MTRTBL: mu_tbl_destroy(m); return; 25 | case MTFN: mu_fn_destroy(m); return; 26 | default: mu_unreachable; 27 | } 28 | } 29 | 30 | 31 | // Frame operations 32 | void mu_frameconvert(mcnt_t sc, mcnt_t dc, mu_t *frame) { 33 | if (dc != 0xf && sc != 0xf) { 34 | for (muint_t i = dc; i < sc; i++) { 35 | mu_dec(frame[i]); 36 | } 37 | 38 | for (muint_t i = sc; i < dc; i++) { 39 | frame[i] = 0; 40 | } 41 | } else if (dc != 0xf) { 42 | mu_t t = *frame; 43 | 44 | for (muint_t i = 0; i < dc; i++) { 45 | frame[i] = mu_tbl_lookup(t, mu_num_fromuint(i)); 46 | } 47 | 48 | mu_dec(t); 49 | } else if (sc != 0xf) { 50 | mu_t t = mu_tbl_create(sc); 51 | 52 | for (muint_t i = 0; i < sc; i++) { 53 | mu_tbl_insert(t, mu_num_fromuint(i), frame[i]); 54 | } 55 | 56 | *frame = t; 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /mu/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu config 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #ifndef MU_CONFIG_H 8 | #define MU_CONFIG_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | // Determine if mu is 32-bit or 64-bit 17 | #if !defined(MU32) && !defined(MU64) 18 | #if UINT32_MAX == UINTPTR_MAX 19 | #define MU32 20 | #elif UINT64_MAX == UINTPTR_MAX 21 | #define MU64 22 | #else 23 | #error "Unspecified word size for Mu" 24 | #endif 25 | #endif 26 | 27 | 28 | // Flags for Mu options 29 | //#define MU_DEBUG 30 | #define MU_MALLOC 31 | //#define MU_COMPUTED_GOTO 32 | 33 | 34 | // Definition of macro-like inlined functions 35 | #ifndef MU_DEBUG 36 | #define mu_inline static inline __attribute__((always_inline)) 37 | #else 38 | #define mu_inline static inline 39 | #endif 40 | 41 | // Definition of non-returning functions 42 | #define mu_noreturn __attribute__((noreturn)) void 43 | 44 | // Definition of pure functions 45 | #define mu_pure __attribute__((const)) 46 | 47 | // Definition of unused variables 48 | #define mu_unused __attribute__((unused)) 49 | 50 | // Definition of alignment for Mu types 51 | #define mu_aligned(x) __attribute__((__aligned__(x))) 52 | 53 | // Builtin for offset of structure members 54 | #define mu_offsetof(t, m) __builtin_offsetof(t, m) 55 | 56 | // Builtin for an unreachable point in code 57 | #define mu_unreachable __builtin_unreachable() 58 | 59 | // Builtin for the next power of two 60 | #ifdef MU32 61 | #define mu_npw2(x) (32 - __builtin_clz((x)-1)) 62 | #else 63 | #define mu_npw2(x) (64 - __builtin_clzl((x)-1)) 64 | #endif 65 | 66 | // Builtin for finding next alignment for pointers 67 | #define mu_align(x) (((x) + sizeof(uintptr_t)-1) & ~(sizeof(uintptr_t)-1)) 68 | 69 | // Definition of Mu specific assert function 70 | #ifdef MU_DEBUG 71 | #include 72 | #define mu_assert(x) assert(x) 73 | #else 74 | #define mu_assert(x) (void)0 75 | #endif 76 | 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /mu/parse.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu parsing and compilation 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #ifndef MU_PARSE_H 8 | #define MU_PARSE_H 9 | #include "config.h" 10 | #include "types.h" 11 | 12 | 13 | // Print parsable representation of literals 14 | mu_t mu_repr(mu_t m, mu_t depth); 15 | 16 | // Parse literals without side-effects 17 | mu_t mu_parsen(const mbyte_t **s, const mbyte_t *end); 18 | mu_t mu_parse(const char *s, muint_t n); 19 | 20 | // Compile Mu source code into code objects 21 | mu_t mu_compilen(const mbyte_t **s, const mbyte_t *end, mu_t scope); 22 | mu_t mu_compile(const char *s, muint_t n, mu_t scope); 23 | 24 | 25 | // Language keywords 26 | #define MU_KEYWORDS mu_keywords_def() 27 | 28 | #define MU_KW_LET mu_kw_let_def() 29 | #define MU_KW_ELSE mu_kw_else_def() 30 | #define MU_KW_AND mu_kw_and_def() 31 | #define MU_KW_OR mu_kw_or_def() 32 | #define MU_KW_CONT mu_kw_continue_def() 33 | #define MU_KW_BREAK mu_kw_break_def() 34 | #define MU_KW_RETURN mu_kw_return_def() 35 | #define MU_KW_FN mu_kw_fn_def() 36 | #define MU_KW_TYPE mu_kw_type_def() 37 | #define MU_KW_IF mu_kw_if_def() 38 | #define MU_KW_WHILE mu_kw_while_def() 39 | #define MU_KW_FOR mu_kw_for_def() 40 | #define MU_KW_NIL mu_kw_nil_def() 41 | #define MU_KW_NIL2 mu_kw_nil2_def() 42 | #define MU_KW_ASSIGN mu_kw_assign_def() 43 | #define MU_KW_PAIR mu_kw_pair_def() 44 | #define MU_KW_DOT mu_kw_dot_def() 45 | #define MU_KW_ARROW mu_kw_arrow_def() 46 | #define MU_KW_EXPAND mu_kw_expand_def() 47 | 48 | MU_DEF(mu_keywords_def) 49 | 50 | MU_DEF(mu_kw_let_def) 51 | MU_DEF(mu_kw_else_def) 52 | MU_DEF(mu_kw_and_def) 53 | MU_DEF(mu_kw_or_def) 54 | MU_DEF(mu_kw_continue_def) 55 | MU_DEF(mu_kw_break_def) 56 | MU_DEF(mu_kw_return_def) 57 | MU_DEF(mu_kw_fn_def) 58 | MU_DEF(mu_kw_type_def) 59 | MU_DEF(mu_kw_if_def) 60 | MU_DEF(mu_kw_while_def) 61 | MU_DEF(mu_kw_for_def) 62 | MU_DEF(mu_kw_nil_def) 63 | MU_DEF(mu_kw_nil2_def) 64 | MU_DEF(mu_kw_assign_def) 65 | MU_DEF(mu_kw_pair_def) 66 | MU_DEF(mu_kw_dot_def) 67 | MU_DEF(mu_kw_arrow_def) 68 | MU_DEF(mu_kw_expand_def) 69 | 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /mu/vm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu virtual machine 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #ifndef MU_VM_H 8 | #define MU_VM_H 9 | #include "config.h" 10 | #include "types.h" 11 | #include "fn.h" 12 | 13 | 14 | // Mu uses bytecode as an intermediary representation 15 | // during compilation. The virtual machine then converts 16 | // these opcodes into implementation specific instructions. 17 | // 18 | // The bytecode represents the execution of a register based 19 | // machine that operates on Mu values. Operations can have from 20 | // 1 to 3 operands named d, a, and b and their ranges are limited 21 | // by the underlying virtual machine's implementation. 22 | // 23 | // In order to ensure correct reference counting without significantly 24 | // more bytecode, some operations consume their arguments. Reference 25 | // counting is indicated by a trailing +/-. Because of reference 26 | // counting, registers may or may not contain valid Mu values, and values 27 | // may remain in use after decrementing. 28 | // 29 | // The special register r0 contains the scope of the current function. 30 | typedef enum mop { 31 | /* opcode encoding operation description */ 32 | MU_OP_IMM = 0x6, /* rd = imms[a] loads immediate */ 33 | MU_OP_FN = 0x7, /* rd = fn(fns[a], r0) creates new function in the scope */ 34 | MU_OP_TBL = 0x8, /* rd = tbl(a) creates new empty table */ 35 | 36 | MU_OP_MOVE = 0x3, /* rd = ra moves register */ 37 | MU_OP_DUP = 0x4, /* rd = ra+ copies and increments register */ 38 | MU_OP_DROP = 0x5, /* rd- decrements register */ 39 | 40 | MU_OP_LOOKUP = 0xa, /* rd = ra[rb-] table lookup */ 41 | MU_OP_LOOKDN = 0x9, /* rd = ra-[rb-] table lookup which drops table */ 42 | MU_OP_INSERT = 0xb, /* ra[rb-] = rd- nonrecursive table insert */ 43 | MU_OP_ASSIGN = 0xc, /* ra[rb-] = rd- recursive table assign */ 44 | 45 | MU_OP_JUMP = 0xf, /* pc = pc + a jumps to pc offset */ 46 | MU_OP_JTRUE = 0xe, /* if (rd) pc = pc + a conditionally jumps if not nil */ 47 | MU_OP_JFALSE = 0xd, /* if (!rd) pc = pc + a conditionally jumps if nil */ 48 | 49 | MU_OP_CALL = 0x2, /* rd..d+b-1 = rd-(rd+1..d+a) performs function call */ 50 | MU_OP_TCALL = 0x1, /* return rd-(rd+1..d+a) performs tail recursive call */ 51 | MU_OP_RET = 0x0, /* return rd..d+b-1 returns values */ 52 | } mop_t; 53 | 54 | 55 | // Encode opcode 56 | void mu_encode(void (*emit)(void *, mbyte_t), void *p, 57 | mop_t op, mint_t d, mint_t a, mint_t b); 58 | 59 | // Replace jump with actual jump distance and returns previous jump value 60 | // Note: Currently can not change size of jump instruction 61 | mint_t mu_patch(void *c, mint_t j); 62 | 63 | // Execute bytecode 64 | mcnt_t mu_exec(mu_t code, mu_t scope, mu_t *frame); 65 | 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /mu/num.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu num, the representation of numbers 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #ifndef MU_NUM_H 8 | #define MU_NUM_H 9 | #include "config.h" 10 | #include "types.h" 11 | 12 | 13 | // Conversion operations 14 | mu_t mu_num_fromfloat(mfloat_t); 15 | mu_inline mu_t mu_num_fromuint(muint_t n); 16 | mu_inline mu_t mu_num_fromint(mint_t n); 17 | mu_t mu_num_frommu(mu_t m); 18 | 19 | // Number accessing functions 20 | mu_inline mfloat_t mu_num_getfloat(mu_t m); 21 | mu_inline muint_t mu_num_getuint(mu_t m); 22 | mu_inline mint_t mu_num_getint(mu_t m); 23 | muint_t mu_num_clampuint(mu_t m, muint_t lower, muint_t upper); 24 | mint_t mu_num_clampint(mu_t m, mint_t lower, mint_t upper); 25 | 26 | // Comparison operation 27 | mint_t mu_num_cmp(mu_t, mu_t); 28 | 29 | // Arithmetic operations 30 | mu_t mu_num_neg(mu_t); 31 | mu_t mu_num_add(mu_t, mu_t); 32 | mu_t mu_num_sub(mu_t, mu_t); 33 | mu_t mu_num_mul(mu_t, mu_t); 34 | mu_t mu_num_div(mu_t, mu_t); 35 | mu_t mu_num_idiv(mu_t, mu_t); 36 | mu_t mu_num_mod(mu_t, mu_t); 37 | mu_t mu_num_pow(mu_t, mu_t); 38 | mu_t mu_num_log(mu_t, mu_t); 39 | 40 | mu_t mu_num_abs(mu_t); 41 | mu_t mu_num_floor(mu_t); 42 | mu_t mu_num_ceil(mu_t); 43 | 44 | // Trig operations 45 | mu_t mu_num_cos(mu_t); 46 | mu_t mu_num_acos(mu_t); 47 | mu_t mu_num_sin(mu_t); 48 | mu_t mu_num_asin(mu_t); 49 | mu_t mu_num_tan(mu_t); 50 | mu_t mu_num_atan(mu_t, mu_t); 51 | 52 | // Bitwise operations 53 | mu_t mu_num_not(mu_t); 54 | mu_t mu_num_and(mu_t, mu_t); 55 | mu_t mu_num_or(mu_t, mu_t); 56 | mu_t mu_num_xor(mu_t, mu_t); 57 | 58 | mu_t mu_num_shl(mu_t, mu_t); 59 | mu_t mu_num_shr(mu_t, mu_t); 60 | 61 | // Number representation 62 | mu_t mu_num_parsen(const mbyte_t **pos, const mbyte_t *end); 63 | mu_t mu_num_parse(const char *s, muint_t n); 64 | mu_t mu_num_repr(mu_t); 65 | 66 | mu_t mu_num_bin(mu_t); 67 | mu_t mu_num_oct(mu_t); 68 | mu_t mu_num_hex(mu_t); 69 | 70 | 71 | // Number creating functions 72 | mu_inline mu_t mu_num_fromuint(muint_t n) { 73 | return (mu_t)(MTNUM + (~7 & 74 | ((union { mfloat_t n; muint_t u; }){(mfloat_t)n}).u)); 75 | } 76 | 77 | mu_inline mu_t mu_num_fromint(mint_t n) { 78 | return (mu_t)(MTNUM + (~7 & 79 | ((union { mfloat_t n; muint_t u; }){(mfloat_t)n}).u)); 80 | } 81 | 82 | // Number accessing functions 83 | mu_inline mfloat_t mu_num_getfloat(mu_t m) { 84 | return ((union { muint_t u; mfloat_t n; }){(muint_t)m - MTNUM}).n; 85 | } 86 | 87 | mu_inline muint_t mu_num_getuint(mu_t m) { 88 | return (muint_t)mu_num_getfloat(m); 89 | } 90 | 91 | mu_inline mint_t mu_num_getint(mu_t m) { 92 | return (mint_t)mu_num_getfloat(m); 93 | } 94 | 95 | 96 | // Number constant macro 97 | #define MU_DEF_FLOAT(name, num) \ 98 | mu_pure mu_t name(void) { \ 99 | return (mu_t)(MTNUM + (~7 & \ 100 | ((union { mfloat_t n; muint_t u; }){(mfloat_t)num}).u)); \ 101 | } 102 | 103 | #define MU_DEF_UINT(name, num) MU_DEF_FLOAT(name, (muint_t)num) 104 | #define MU_DEF_INT(name, num) MU_DEF_FLOAT(name, (mint_t)num) 105 | 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /mu/str.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu strs, the representation of strings 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #ifndef MU_STR_H 8 | #define MU_STR_H 9 | #include "config.h" 10 | #include "types.h" 11 | #include "buf.h" 12 | 13 | 14 | // Definition of Mu's string types 15 | // Storage follows identical layout of buf type. 16 | // Strings must be interned before use in tables, and once interned, 17 | // strings cannot be mutated without breaking things. 18 | struct mstr { 19 | mref_t ref; // reference count 20 | mlen_t len; // length of string 21 | mbyte_t data[]; // data follows 22 | }; 23 | 24 | 25 | // String creation functions 26 | mu_t mu_str_intern(mu_t buf, muint_t n); 27 | 28 | // Conversion operations 29 | mu_t mu_str_fromdata(const void *s, muint_t n); 30 | mu_inline mu_t mu_str_fromcstr(const char *s); 31 | mu_inline mu_t mu_str_fromc(char s); 32 | mu_t mu_str_frommu(mu_t m); 33 | 34 | // String access functions 35 | mu_inline mlen_t mu_str_getlen(mu_t m); 36 | mu_inline const void *mu_str_getdata(mu_t m); 37 | 38 | // Formatting 39 | mu_t mu_str_vformat(const char *f, va_list args); 40 | mu_t mu_str_format(const char *f, ...); 41 | 42 | // Comparison operation 43 | mint_t mu_str_cmp(mu_t a, mu_t b); 44 | 45 | // String operations 46 | mu_t mu_str_concat(mu_t a, mu_t b); 47 | mu_t mu_str_subset(mu_t s, mint_t lower, mint_t upper); 48 | 49 | // String iteration 50 | bool mu_str_next(mu_t s, muint_t *i, mu_t *c); 51 | mu_t mu_str_iter(mu_t s); 52 | 53 | // String representation 54 | mu_t mu_str_parsen(const mbyte_t **pos, const mbyte_t *end); 55 | mu_t mu_str_parse(const char *s, muint_t n); 56 | mu_t mu_str_repr(mu_t s); 57 | 58 | 59 | // String creation stuff 60 | mu_inline mu_t mu_str_fromcstr(const char *s) { 61 | return mu_str_fromdata(s, strlen(s)); 62 | } 63 | 64 | mu_inline mu_t mu_str_fromc(char s) { 65 | return mu_str_fromdata(&s, 1); 66 | } 67 | 68 | // String access functions 69 | // we don't define a string struct 70 | mu_inline mlen_t mu_str_getlen(mu_t m) { 71 | return ((struct mstr *)((muint_t)m - MTSTR))->len; 72 | } 73 | 74 | mu_inline const void *mu_str_getdata(mu_t m) { 75 | return ((struct mstr *)((muint_t)m - MTSTR))->data; 76 | } 77 | 78 | 79 | // String constant macro 80 | #define MU_DEF_STR(name, s) \ 81 | mu_pure mu_t name(void) { \ 82 | static mu_t ref = 0; \ 83 | static const struct { \ 84 | mref_t ref; \ 85 | mlen_t len; \ 86 | mbyte_t data[sizeof s > 1 ? (sizeof s)-1 : 1]; \ 87 | } inst = {0, (sizeof s)-1, s}; \ 88 | \ 89 | extern mu_t mu_str_init(const struct mstr *); \ 90 | if (!ref) { \ 91 | ref = mu_str_init((const struct mstr *)&inst); \ 92 | } \ 93 | \ 94 | return ref; \ 95 | } 96 | 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /mu/types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Type definitions for Mu 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #ifndef MU_TYPES_H 8 | #define MU_TYPES_H 9 | #include "config.h" 10 | 11 | 12 | // Definitions of the basic types used in Mu 13 | // Default, half-sized, and quarter sized integer types 14 | // 15 | // Requires sizeof(muint_t) == sizeof(void *) 16 | // 17 | // The other sizes are used for struct packing 18 | #ifdef MU32 19 | typedef int8_t mintq_t; 20 | typedef uint8_t muintq_t; 21 | typedef int16_t minth_t; 22 | typedef uint16_t muinth_t; 23 | typedef int32_t mint_t; 24 | typedef uint32_t muint_t; 25 | #else 26 | typedef int16_t mintq_t; 27 | typedef uint16_t muintq_t; 28 | typedef int32_t minth_t; 29 | typedef uint32_t muinth_t; 30 | typedef int64_t mint_t; 31 | typedef uint64_t muint_t; 32 | #endif 33 | 34 | // Currently the num type is just based on floats, 35 | // although an integer implementation may be possible 36 | // 37 | // Requires sizeof(mfloat_t) <= sizeof(muint_t) 38 | #ifdef MU32 39 | typedef float mfloat_t; 40 | #else 41 | typedef double mfloat_t; 42 | #endif 43 | 44 | // Smallest addressable unit, used for strings and bufs 45 | typedef unsigned char mbyte_t; 46 | 47 | // Length type for strings and tables 48 | typedef muinth_t mlen_t; 49 | 50 | 51 | // Reference type for reference counting, alignment is 52 | // required for tagging pointers with mu types. The size 53 | // doesn't matter too much, because if the reference count 54 | // overflows, the variable just becomes constant. 55 | typedef mu_aligned(8) muinth_t mref_t; 56 | 57 | // Smallest allocatable size 58 | #define MU_MINALLOC (4*sizeof(muint_t)) 59 | 60 | // Tags for mu types. The tag is a three bit type specifier 61 | // located in lowest bits of each variable. 62 | // 3b00x indicates type is not reference counted 63 | typedef enum mtype { 64 | MTNIL = 0, // nil 65 | MTNUM = 1, // number 66 | MTSTR = 3, // string 67 | MTBUF = 2, // buffer 68 | MTDBUF = 6, // managed buffer 69 | MTTBL = 4, // table 70 | MTRTBL = 5, // read-only table 71 | MTFN = 7, // function 72 | } mtype_t; 73 | 74 | // Here is the heart of Mu, the mu_t type 75 | // 76 | // Doesn't necessarily point to anything, but using a 77 | // void* would risk unwanted implicit conversions. 78 | typedef struct mu *mu_t; 79 | 80 | // Access to mu type components 81 | mu_inline mtype_t mu_gettype(mu_t m) { return 7 & (muint_t)m; } 82 | mu_inline mref_t mu_getref(mu_t m) { return *(mref_t *)(~7 & (muint_t)m); } 83 | 84 | // Properties of variables 85 | mu_inline bool mu_isnil(mu_t m) { return !m; } 86 | mu_inline bool mu_isnum(mu_t m) { return mu_gettype(m) == MTNUM; } 87 | mu_inline bool mu_isstr(mu_t m) { return mu_gettype(m) == MTSTR; } 88 | mu_inline bool mu_isbuf(mu_t m) { return (3 & (muint_t)m) == MTBUF; } 89 | mu_inline bool mu_istbl(mu_t m) { return (6 & (muint_t)m) == MTTBL; } 90 | mu_inline bool mu_isfn(mu_t m) { return mu_gettype(m) == MTFN; } 91 | mu_inline bool mu_isref(mu_t m) { return 6 & (muint_t)m; } 92 | 93 | // Reference counting for mu types 94 | // 95 | // Deallocates immediately when reference count hits zero. If a type 96 | // does have zero, this indicates the variable is constant and may be 97 | // statically allocated. As a nice side effect, overflow results in 98 | // constant variables. 99 | mu_inline mu_t mu_inc(mu_t m) { 100 | if (mu_isref(m)) { 101 | mref_t *ref = (mref_t *)(~7 & (muint_t)m); 102 | mref_t count = *ref; 103 | 104 | if (count != 0) { 105 | count++; 106 | *ref = count; 107 | } 108 | } 109 | 110 | return m; 111 | } 112 | 113 | mu_inline void mu_dec(mu_t m) { 114 | if (mu_isref(m)) { 115 | mref_t *ref = (mref_t *)(~7 & (muint_t)m); 116 | mref_t count = *ref; 117 | 118 | if (count != 0) { 119 | count--; 120 | *ref = count; 121 | 122 | if (count == 0) { 123 | extern void mu_destroy(mu_t m); 124 | mu_destroy(m); 125 | } 126 | } 127 | } 128 | } 129 | 130 | 131 | // Multiple variables can be passed in a frame, 132 | // which is a small array of MU_FRAME elements. 133 | // 134 | // If more than MU_FRAME elements need to be passed, the 135 | // frame count of 0xf indicates a table containing the true 136 | // elements is passed as the first value in the frame. 137 | // 138 | // For function calls, the frame count is split into two 139 | // nibbles for arguments and return values, in that order. 140 | #define MU_FRAME 4 141 | 142 | // Type for frame counts, for functions calls, the two nibbles 143 | // are used for arguments and return values seperately. 144 | typedef uint8_t mcnt_t; 145 | 146 | // Frame operations 147 | mu_inline mlen_t mu_framecount(mcnt_t fc) { 148 | return (fc > MU_FRAME) ? 1 : fc; 149 | } 150 | 151 | mu_inline void mu_framemove(mcnt_t fc, mu_t *dframe, mu_t *sframe) { 152 | memcpy(dframe, sframe, sizeof(mu_t)*mu_framecount(fc)); 153 | } 154 | 155 | void mu_frameconvert(mcnt_t sc, mcnt_t dc, mu_t *frame); 156 | 157 | 158 | // Declaration of mu constants, requires other MU_DEF_* for definition 159 | #define MU_DEF(name) \ 160 | extern mu_pure mu_t name(void); 161 | 162 | 163 | #endif 164 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu example program for unix-like systems 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #include "mu/mu.h" 8 | #include "repl/repl.h" 9 | 10 | #ifndef MU_NO_DIS 11 | #include "dis/dis.h" 12 | #define MU_DIS_ENTRY { mu_dis_key_def, mu_dis_module_def } 13 | #else 14 | #define MU_DIS_ENTRY { NULL, NULL } 15 | #endif 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #define BLOCK_SIZE 512 24 | #define HISTORY_LEN 256 25 | 26 | 27 | // Global state 28 | const char **argv; 29 | 30 | static struct { 31 | bool execute; 32 | bool interpret; 33 | bool load; 34 | } mode; 35 | 36 | // Mu state 37 | static mu_t scope = 0; 38 | static mu_t args = 0; 39 | 40 | static void init_scope(void) { 41 | scope = mu_tbl_createtail(0, MU_BUILTINS); 42 | } 43 | 44 | static void init_args(void) { 45 | args = mu_tbl_create(0); 46 | while (*argv) { 47 | mu_tbl_insert(args, mu_num_fromuint(mu_tbl_getlen(args)), 48 | mu_str_format("%s", *argv++)); 49 | } 50 | } 51 | 52 | 53 | // System functions 54 | jmp_buf error_jmp; 55 | 56 | mu_noreturn mu_sys_error(const char *m, muint_t len) { 57 | printf("\x1b[31merror: %.*s\x1b[0m\n", (unsigned)len, m); 58 | longjmp(error_jmp, 1); 59 | } 60 | 61 | void mu_sys_print(const char *m, muint_t len) { 62 | printf("%.*s\n", (unsigned)len, m); 63 | } 64 | 65 | 66 | MU_DEF_TBL(mu_sys_imports_def, { 67 | MU_DIS_ENTRY, 68 | }) 69 | 70 | mu_t mu_sys_import(mu_t name) { 71 | mu_t module = mu_tbl_lookup(mu_sys_imports_def(), name); 72 | return module; 73 | } 74 | 75 | 76 | // Operations 77 | static void execute(const char *input) { 78 | if (!setjmp(error_jmp)) { 79 | mu_eval(input, strlen(input), scope, 0); 80 | } 81 | } 82 | 83 | static void load_file(FILE *file) { 84 | if (!setjmp(error_jmp)) { 85 | mu_t buffer = mu_buf_create(0); 86 | muint_t n = 0; 87 | 88 | while (true) { 89 | mu_buf_push(&buffer, &n, BLOCK_SIZE); 90 | size_t read = fread( 91 | (mbyte_t*)mu_buf_getdata(buffer) + n - BLOCK_SIZE, 92 | 1, BLOCK_SIZE, file); 93 | 94 | if (read < BLOCK_SIZE) { 95 | break; 96 | } 97 | } 98 | 99 | if (ferror(file)) { 100 | mu_errorf("io error reading file (%d)", errno); 101 | } 102 | 103 | mu_eval(mu_buf_getdata(buffer), n, scope, 0); 104 | mu_dec(buffer); 105 | } 106 | } 107 | 108 | static void load(const char *name) { 109 | if (!setjmp(error_jmp)) { 110 | FILE *file; 111 | if (!(file = fopen(name, "r"))) { 112 | mu_errorf("io error opening file (%d)", errno); 113 | } 114 | 115 | load_file(file); 116 | 117 | fclose(file); 118 | } 119 | } 120 | 121 | static int interpret() { 122 | while (true) { 123 | if (!setjmp(error_jmp)) { 124 | mu_repl("> ", scope); 125 | } 126 | } 127 | 128 | mu_unreachable; 129 | } 130 | 131 | static int run() { 132 | mu_t mainfn = mu_tbl_lookup(scope, mu_str_format("main")); 133 | if (!mainfn || !mu_isfn(mainfn)) { 134 | return 0; 135 | } 136 | 137 | mu_t code = mu_fn_call(mainfn, 0xf1, args); 138 | return mu_num_getint(code); 139 | } 140 | 141 | 142 | // Entry point 143 | static mu_noreturn usage(const char *name) { 144 | printf("\n" 145 | "usage: %s [options] [program] [args]\n" 146 | "options:\n" 147 | " -e string execute string before program\n" 148 | " -l file import and execute file before program\n" 149 | " -i run interactively after program\n" 150 | " -- stop handling options\n" 151 | "program: file to execute and run or '-' for stdin\n" 152 | "args: arguments passed to running program\n" 153 | "\n", name); 154 | 155 | exit(-1); 156 | } 157 | 158 | static void options(void) { 159 | const char *name = *argv++; 160 | 161 | while (*argv && (*argv)[0] == '-') { 162 | muint_t len = strlen(*argv); 163 | if (len > 2) { 164 | usage(name); 165 | } 166 | 167 | switch ((*argv++)[1]) { 168 | case 'e': 169 | if (!*argv) { 170 | usage(name); 171 | } 172 | 173 | execute(*argv++); 174 | mode.execute = true; 175 | break; 176 | 177 | case 'l': 178 | if (!*argv) { 179 | usage(name); 180 | } 181 | 182 | load(*argv++); 183 | break; 184 | 185 | case 'i': 186 | mode.interpret = true; 187 | break; 188 | 189 | case '\0': 190 | mode.load = true; 191 | return; 192 | 193 | case '-': 194 | return; 195 | 196 | default: 197 | usage(name); 198 | } 199 | } 200 | } 201 | 202 | int main(int argc1, const char **argv1) { 203 | argv = argv1; 204 | 205 | init_scope(); 206 | options(); 207 | 208 | if (mode.load || *argv) { 209 | if (mode.load) { 210 | load_file(stdin); 211 | } else { 212 | load(*argv++); 213 | } 214 | 215 | mode.load = true; 216 | } 217 | 218 | init_args(); 219 | 220 | if (mode.interpret || (!mode.load && !mode.execute)) { 221 | return interpret(); 222 | } else { 223 | return run(); 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /mu/fn.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu fns, first class functions 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #ifndef MU_FN_H 8 | #define MU_FN_H 9 | #include "config.h" 10 | #include "types.h" 11 | #include "buf.h" 12 | 13 | 14 | // Definition of C Function types 15 | typedef mcnt_t mbfn_t(mu_t *frame); 16 | typedef mcnt_t msbfn_t(mu_t closure, mu_t *frame); 17 | 18 | // Function tags 19 | enum mu_fn_flags { 20 | MU_FN_BUILTIN = 1 << 0, // C builtin function 21 | MU_FN_SCOPED = 1 << 1, // Closure attached to function 22 | MU_FN_WEAK = 1 << 2, // Closure is weakly referenced 23 | }; 24 | 25 | // Definition of the function type 26 | // 27 | // Functions are stored as function pointers paired with closures. 28 | // Additionally several flags are defined to specify how the 29 | // function should be called. 30 | struct mfn { 31 | mref_t ref; // reference count 32 | mcnt_t args; // argument count 33 | uint8_t flags; // function flags 34 | 35 | mu_t closure; // function closure 36 | 37 | union { 38 | mbfn_t *bfn; // c function 39 | msbfn_t *sbfn; // scoped c function 40 | mu_t code; // compiled mu code 41 | } fn; 42 | }; 43 | 44 | 45 | // Conversion operations 46 | mu_t mu_fn_frombfn(mcnt_t args, mbfn_t *bfn); 47 | mu_t mu_fn_fromsbfn(mcnt_t args, msbfn_t *sbfn, mu_t closure); 48 | mu_t mu_fn_fromcode(mu_t code, mu_t closure); 49 | mu_t mu_fn_frommu(mu_t m); 50 | 51 | // Function access 52 | mu_inline mu_t mu_fn_getcode(mu_t m); 53 | mu_inline mu_t mu_fn_getclosure(mu_t m); 54 | 55 | // Function calls 56 | mcnt_t mu_fn_tcall(mu_t f, mcnt_t fc, mu_t *frame); 57 | void mu_fn_fcall(mu_t f, mcnt_t fc, mu_t *frame); 58 | mu_t mu_fn_vcall(mu_t f, mcnt_t fc, va_list args); 59 | mu_t mu_fn_call(mu_t f, mcnt_t fc, ...); 60 | 61 | // Iteration 62 | bool mu_fn_next(mu_t f, mcnt_t fc, mu_t *frame); 63 | 64 | // Bind and composition 65 | mu_t mu_fn_bind(mu_t f, mu_t args); 66 | mu_t mu_fn_comp(mu_t f, mu_t g); 67 | 68 | 69 | // Definition of code structure used to represent the 70 | // executable component of Mu functions. 71 | struct mcode { 72 | mcnt_t args; // argument count 73 | uint8_t flags; // function flags 74 | muintq_t regs; // number of registers 75 | muintq_t locals; // size of scope 76 | 77 | mlen_t icount; // number of immediate values 78 | mlen_t bcount; // number of bytecode instructions 79 | 80 | mu_t data[]; // data that follows code header 81 | // immediate values 82 | // bytecode 83 | }; 84 | 85 | 86 | // Code checking 87 | mu_inline bool mu_iscode(mu_t m); 88 | 89 | // Code access functions 90 | mu_inline mlen_t mu_code_getimmslen(mu_t c); 91 | mu_inline mlen_t mu_code_getbcodelen(mu_t c); 92 | mu_inline mu_t *mu_code_getimms(mu_t c); 93 | mu_inline void *mu_code_getbcode(mu_t c); 94 | 95 | 96 | // Code checking 97 | mu_inline bool mu_iscode(mu_t m) { 98 | extern void mu_code_destroy(mu_t); 99 | return mu_isbuf(m) && mu_buf_getdtor(m) == mu_code_destroy; 100 | } 101 | 102 | // Code access functions 103 | mu_inline mcnt_t mu_code_getargs(mu_t c) { 104 | return ((struct mcode *)mu_buf_getdata(c))->args; 105 | } 106 | 107 | mu_inline uint8_t mu_code_getflags(mu_t c) { 108 | return ((struct mcode *)mu_buf_getdata(c))->flags; 109 | } 110 | 111 | mu_inline muintq_t mu_code_getregs(mu_t c) { 112 | return ((struct mcode *)mu_buf_getdata(c))->regs; 113 | } 114 | 115 | mu_inline muintq_t mu_code_getlocals(mu_t c) { 116 | return ((struct mcode *)mu_buf_getdata(c))->locals; 117 | } 118 | 119 | mu_inline mlen_t mu_code_getimmslen(mu_t c) { 120 | return ((struct mcode *)mu_buf_getdata(c))->icount; 121 | } 122 | 123 | mu_inline mlen_t mu_code_getbcodelen(mu_t c) { 124 | return ((struct mcode *)mu_buf_getdata(c))->bcount; 125 | } 126 | 127 | mu_inline mu_t *mu_code_getimms(mu_t c) { 128 | return ((struct mcode *)mu_buf_getdata(c))->data; 129 | } 130 | 131 | mu_inline void *mu_code_getbcode(mu_t c) { 132 | return mu_code_getimms(c) + mu_code_getimmslen(c); 133 | } 134 | 135 | // Function access 136 | mu_inline mu_t mu_fn_getcode(mu_t m) { 137 | if (!(((struct mfn *)((muint_t)m - MTFN))->flags & MU_FN_BUILTIN)) { 138 | return mu_inc(((struct mfn *)((muint_t)m - MTFN))->fn.code); 139 | } else { 140 | return 0; 141 | } 142 | } 143 | 144 | mu_inline mu_t mu_fn_getclosure(mu_t m) { 145 | return mu_inc(((struct mfn *)((muint_t)m - MTFN))->closure); 146 | } 147 | 148 | 149 | // Function constant macro 150 | #define MU_DEF_BFN(name, args, bfn) \ 151 | mu_pure mu_t name(void) { \ 152 | static const struct mfn inst = { \ 153 | 0, args, MU_FN_BUILTIN, 0, {bfn}}; \ 154 | return (mu_t)((muint_t)&inst + MTFN); \ 155 | } 156 | 157 | #define MU_DEF_SBFN(name, args, sbfn, closure) \ 158 | mu_pure mu_t name(void) { \ 159 | static mu_t ref = 0; \ 160 | static struct mfn inst = { \ 161 | 0, args, MU_FN_BUILTIN | MU_FN_SCOPED, 0, {sbfn}}; \ 162 | \ 163 | if (!ref) { \ 164 | mu_t (*closuredef)(void) = closure; \ 165 | if (closuredef) { \ 166 | inst.closure = closuredef(); \ 167 | } \ 168 | \ 169 | ref = (mu_t)((muint_t)&inst + MTFN); \ 170 | } \ 171 | \ 172 | return ref; \ 173 | } 174 | 175 | 176 | #endif 177 | -------------------------------------------------------------------------------- /mu/tbl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu tbls, key-value lookup tables 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #ifndef MU_TBL_H 8 | #define MU_TBL_H 9 | #include "config.h" 10 | #include "types.h" 11 | 12 | 13 | // Definition of Mu's table type 14 | // 15 | // Each table is composed of an array of values 16 | // with a stride for keys/values. If keys/values 17 | // is not stored in the array it is implicitely 18 | // stored as a range/offset based on the specified 19 | // offset and length. 20 | struct mtbl { 21 | mref_t ref; 22 | mlen_t len; 23 | mlen_t nils; 24 | muintq_t npw2; 25 | muintq_t isize; 26 | 27 | mu_t tail; 28 | mu_t *array; 29 | }; 30 | 31 | 32 | // Table creation functions 33 | mu_t mu_tbl_create(muint_t size); 34 | mu_t mu_tbl_createtail(muint_t size, mu_t tail); 35 | 36 | // Conversion operations 37 | mu_t mu_tbl_fromlist(mu_t *list, muint_t n); 38 | mu_t mu_tbl_frompairs(mu_t (*pairs)[2], muint_t n); 39 | mu_t mu_tbl_frommu(mu_t m); 40 | 41 | // Table access functions 42 | mu_inline mlen_t mu_tbl_getlen(mu_t m); 43 | mu_inline mu_t mu_tbl_gettail(mu_t m); 44 | 45 | // Changing the tail of the table 46 | void mu_tbl_settail(mu_t t, mu_t tail); 47 | 48 | // Create constant reference to table 49 | mu_inline mu_t mu_tbl_const(mu_t t); 50 | 51 | // Recursively looks up a key in the table 52 | // returns either that value or nil 53 | mu_t mu_tbl_lookup(mu_t t, mu_t k); 54 | 55 | // Inserts a value in the table with the given key 56 | // without decending down the tail chain 57 | void mu_tbl_insert(mu_t t, mu_t k, mu_t v); 58 | 59 | // Recursively assigns a value in the table with the given key 60 | // decends down the tail chain until its found 61 | void mu_tbl_assign(mu_t t, mu_t k, mu_t v); 62 | 63 | // Performs iteration on a table 64 | bool mu_tbl_next(mu_t t, muint_t *i, mu_t *k, mu_t *v); 65 | mu_t mu_tbl_iter(mu_t t); 66 | mu_t mu_tbl_pairs(mu_t t); 67 | 68 | // Table representation 69 | mu_t mu_tbl_parsen(const mbyte_t **pos, const mbyte_t *end); 70 | mu_t mu_tbl_parse(const char *s, muint_t n); 71 | mu_t mu_tbl_repr(mu_t t, mu_t depth); 72 | 73 | // Array-like manipulation 74 | void mu_tbl_push(mu_t t, mu_t v, mint_t i); 75 | mu_t mu_tbl_pop(mu_t t, mint_t i); 76 | 77 | mu_t mu_tbl_concat(mu_t a, mu_t b, mu_t offset); 78 | mu_t mu_tbl_subset(mu_t t, mint_t lower, mint_t upper); 79 | 80 | // Set operations 81 | mu_t mu_tbl_and(mu_t a, mu_t b); 82 | mu_t mu_tbl_or(mu_t a, mu_t b); 83 | mu_t mu_tbl_xor(mu_t a, mu_t b); 84 | mu_t mu_tbl_diff(mu_t a, mu_t b); 85 | 86 | 87 | // Table access functions 88 | mu_inline mlen_t mu_tbl_getlen(mu_t m) { 89 | return ((struct mtbl *)((muint_t)m & ~7))->len; 90 | } 91 | 92 | mu_inline mu_t mu_tbl_gettail(mu_t m) { 93 | return mu_inc(((struct mtbl *)((muint_t)m & ~7))->tail); 94 | } 95 | 96 | mu_inline mu_t mu_tbl_const(mu_t t) { 97 | return mu_inc((mu_t)((MTTBL ^ MTRTBL) | (muint_t)t)); 98 | } 99 | 100 | 101 | // Table constant macros 102 | #define MU_DEF_LIST(name, ...) \ 103 | mu_pure mu_t name(void) { \ 104 | static mu_t ref = 0; \ 105 | static mu_t (*const def[])(void) = __VA_ARGS__; \ 106 | static struct mtbl inst = {0}; \ 107 | \ 108 | extern mu_t mu_tbl_initlist(struct mtbl *, \ 109 | mu_t (*const *)(void), muint_t); \ 110 | if (!ref) { \ 111 | ref = mu_tbl_initlist(&inst, def, sizeof(def) / sizeof(def[0])); \ 112 | } \ 113 | \ 114 | return ref; \ 115 | } 116 | 117 | #define MU_DEF_TBL(name, ...) \ 118 | mu_pure mu_t name(void) { \ 119 | static mu_t ref = 0; \ 120 | static mu_t (*const def[][2])(void) = __VA_ARGS__; \ 121 | static struct mtbl inst = {0}; \ 122 | \ 123 | extern mu_t mu_tbl_initpairs(struct mtbl *, mu_t (*)(void), \ 124 | mu_t (*const (*)[2])(void), muint_t); \ 125 | if (!ref) { \ 126 | ref = mu_tbl_initpairs(&inst, 0, \ 127 | def, sizeof(def) / sizeof(def[0])); \ 128 | } \ 129 | \ 130 | return ref; \ 131 | } 132 | 133 | #define MU_DEF_TBLTAIL(name, tail, ...) \ 134 | mu_pure mu_t name(void) { \ 135 | static mu_t ref = 0; \ 136 | static mu_t (*const def[][2])(void) = __VA_ARGS__; \ 137 | static struct mtbl inst = {0}; \ 138 | \ 139 | extern mu_t mu_tbl_initpairs(struct mtbl *, mu_t (*)(void), \ 140 | mu_t (*const (*)[2])(void), muint_t); \ 141 | if (!ref) { \ 142 | ref = mu_tbl_initpairs(&inst, tail, \ 143 | def, sizeof(def) / sizeof(def[0])); \ 144 | } \ 145 | \ 146 | return ref; \ 147 | } 148 | 149 | 150 | #endif 151 | -------------------------------------------------------------------------------- /mu/fn.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu fns, first class functions 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #include "fn.h" 8 | #include "mu.h" 9 | 10 | 11 | // Function access 12 | mu_inline struct mfn *mfn(mu_t f) { 13 | return (struct mfn *)((muint_t)f - MTFN); 14 | } 15 | 16 | 17 | // Creation functions 18 | mu_t mu_fn_fromcode(mu_t c, mu_t closure) { 19 | if (mu_code_getflags(c) & MU_FN_WEAK) { 20 | mu_assert(mu_getref(closure) > 1); 21 | mu_dec(closure); 22 | } 23 | 24 | struct mfn *f = mu_alloc(sizeof(struct mfn)); 25 | f->ref = 1; 26 | f->args = mu_code_getargs(c); 27 | f->flags = mu_code_getflags(c); 28 | f->closure = closure; 29 | f->fn.code = c; 30 | return (mu_t)((muint_t)f + MTFN); 31 | } 32 | 33 | mu_t mu_fn_frombfn(mcnt_t args, mbfn_t *bfn) { 34 | struct mfn *f = mu_alloc(sizeof(struct mfn)); 35 | f->ref = 1; 36 | f->args = args; 37 | f->flags = MU_FN_BUILTIN; 38 | f->closure = 0; 39 | f->fn.bfn = bfn; 40 | return (mu_t)((muint_t)f + MTFN); 41 | } 42 | 43 | mu_t mu_fn_fromsbfn(mcnt_t args, msbfn_t *sbfn, mu_t closure) { 44 | struct mfn *f = mu_alloc(sizeof(struct mfn)); 45 | f->ref = 1; 46 | f->args = args; 47 | f->flags = MU_FN_BUILTIN | MU_FN_SCOPED; 48 | f->closure = closure; 49 | f->fn.sbfn = sbfn; 50 | return (mu_t)((muint_t)f + MTFN); 51 | } 52 | 53 | static mcnt_t mu_id_bfn(mu_t *frame) { 54 | return 0xf; 55 | } 56 | MU_DEF_BFN(mu_id_def, 0xf, mu_id_bfn) 57 | 58 | mu_t mu_fn_frommu(mu_t m) { 59 | switch (mu_gettype(m)) { 60 | case MTNIL: 61 | return mu_id_def(); 62 | 63 | case MTFN: 64 | return m; 65 | 66 | default: 67 | mu_dec(m); 68 | return 0; 69 | } 70 | } 71 | 72 | // Called by garbage collector to clean up 73 | void mu_fn_destroy(mu_t f) { 74 | if (!(mfn(f)->flags & MU_FN_BUILTIN)) { 75 | mu_dec(mfn(f)->fn.code); 76 | } 77 | 78 | if (!(mfn(f)->flags & MU_FN_WEAK)) { 79 | mu_dec(mfn(f)->closure); 80 | } 81 | 82 | mu_dealloc(mfn(f), sizeof(struct mfn)); 83 | } 84 | 85 | void mu_code_destroy(mu_t c) { 86 | for (muint_t i = 0; i < mu_code_getimmslen(c); i++) { 87 | mu_dec(mu_code_getimms(c)[i]); 88 | } 89 | } 90 | 91 | 92 | // C interface for calling functions 93 | mcnt_t mu_fn_tcall(mu_t f, mcnt_t fc, mu_t *frame) { 94 | mu_assert(mu_isfn(f)); 95 | mu_frameconvert(fc, mfn(f)->args, frame); 96 | 97 | switch (mfn(f)->flags & (MU_FN_BUILTIN | MU_FN_SCOPED)) { 98 | case MU_FN_BUILTIN: { 99 | mbfn_t *bfn = mfn(f)->fn.bfn; 100 | mu_dec(f); 101 | return bfn(frame); 102 | } 103 | 104 | case MU_FN_BUILTIN | MU_FN_SCOPED: { 105 | mcnt_t rc = mfn(f)->fn.sbfn(mfn(f)->closure, frame); 106 | mu_dec(f); 107 | return rc; 108 | } 109 | 110 | case MU_FN_SCOPED: { 111 | mu_t c = mu_inc(mfn(f)->fn.code); 112 | mu_t scope = mu_tbl_create(mu_code_getlocals(c)); 113 | mu_tbl_settail(scope, mu_fn_getclosure(f)); 114 | mu_dec(f); 115 | return mu_exec(c, scope, frame); 116 | } 117 | } 118 | 119 | mu_unreachable; 120 | } 121 | 122 | void mu_fn_fcall(mu_t f, mcnt_t fc, mu_t *frame) { 123 | mu_assert(mu_isfn(f)); 124 | mcnt_t rets = mu_fn_tcall(mu_inc(f), fc >> 4, frame); 125 | mu_frameconvert(rets, fc & 0xf, frame); 126 | } 127 | 128 | mu_t mu_fn_vcall(mu_t f, mcnt_t fc, va_list args) { 129 | mu_assert(mu_isfn(f)); 130 | mu_t frame[MU_FRAME]; 131 | 132 | for (muint_t i = 0; i < mu_framecount(fc >> 4); i++) { 133 | frame[i] = va_arg(args, mu_t); 134 | } 135 | 136 | mu_fn_fcall(f, fc, frame); 137 | 138 | for (muint_t i = 1; i < mu_framecount(0xf & fc); i++) { 139 | *va_arg(args, mu_t *) = frame[i]; 140 | } 141 | 142 | return (0xf & fc) ? *frame : 0; 143 | } 144 | 145 | mu_t mu_fn_call(mu_t f, mcnt_t fc, ...) { 146 | mu_assert(mu_isfn(f)); 147 | va_list args; 148 | va_start(args, fc); 149 | mu_t ret = mu_fn_vcall(f, fc, args); 150 | va_end(args); 151 | return ret; 152 | } 153 | 154 | 155 | // Iteration 156 | bool mu_fn_next(mu_t f, mcnt_t fc, mu_t *frame) { 157 | mu_assert(mu_isfn(f)); 158 | mu_fn_fcall(f, (fc == 0) ? 1 : fc, frame); 159 | 160 | if (fc != 0xf) { 161 | if (frame[0]) { 162 | if (fc == 0) { 163 | mu_dec(frame[0]); 164 | } 165 | return true; 166 | } else { 167 | mu_frameconvert(fc, 0, frame); 168 | return false; 169 | } 170 | } else { 171 | mu_t m = mu_tbl_lookup(frame[0], mu_num_fromuint(0)); 172 | if (m) { 173 | mu_dec(m); 174 | return true; 175 | } else { 176 | mu_dec(frame[0]); 177 | return false; 178 | } 179 | } 180 | } 181 | 182 | 183 | // Function related Mu functions 184 | 185 | static mcnt_t mu_fn_bfn(mu_t *frame) { 186 | mu_t m = mu_fn_frommu(mu_inc(frame[0])); 187 | mu_checkargs(m, MU_FN_KEY, 0x1, frame); 188 | mu_dec(frame[0]); 189 | frame[0] = m; 190 | return 1; 191 | } 192 | 193 | MU_DEF_STR(mu_fn_key_def, "fn_") 194 | MU_DEF_BFN(mu_fn_def, 0x1, mu_fn_bfn) 195 | 196 | // Binds arguments to function 197 | static mcnt_t mu_fn_bound(mu_t scope, mu_t *frame) { 198 | mu_t f = mu_tbl_lookup(scope, mu_num_fromuint(0)); 199 | mu_t args = mu_tbl_lookup(scope, mu_num_fromuint(1)); 200 | 201 | frame[0] = mu_tbl_concat(args, frame[0], 0); 202 | return mu_fn_tcall(f, 0xf, frame); 203 | } 204 | 205 | mu_t mu_fn_bind(mu_t f, mu_t g) { 206 | mu_assert(mu_isfn(f) && mu_istbl(g)); 207 | return mu_fn_fromsbfn(0xf, mu_fn_bound, 208 | mu_tbl_fromlist((mu_t[]){mu_inc(f), g}, 2)); 209 | } 210 | 211 | static mcnt_t mu_bind_bfn(mu_t *frame) { 212 | mu_t f = mu_tbl_pop(frame[0], 0); 213 | mu_checkargs(mu_isfn(f), MU_BIND_KEY, 0x2, (mu_t[]){f, frame[0]}); 214 | 215 | frame[0] = mu_fn_bind(f, frame[0]); 216 | mu_dec(f); 217 | return 1; 218 | } 219 | 220 | MU_DEF_STR(mu_bind_key_def, "bind") 221 | MU_DEF_BFN(mu_bind_def, 0xf, mu_bind_bfn) 222 | 223 | static mcnt_t mu_fn_composed(mu_t fs, mu_t *frame) { 224 | mcnt_t c = 0xf; 225 | for (muint_t i = mu_tbl_getlen(fs)-1; i+1 > 0; i--) { 226 | mu_t f = mu_tbl_lookup(fs, mu_num_fromuint(i)); 227 | c = mu_fn_tcall(f, c, frame); 228 | } 229 | 230 | return c; 231 | } 232 | 233 | mu_t mu_fn_comp(mu_t f, mu_t g) { 234 | mu_assert(mu_isfn(f) && mu_isfn(g)); 235 | return mu_fn_fromsbfn(0xf, mu_fn_composed, 236 | mu_tbl_fromlist((mu_t[]){mu_inc(f), g}, 2)); 237 | } 238 | 239 | static mcnt_t mu_comp_bfn(mu_t *frame) { 240 | mu_t f = frame[0]; 241 | mu_t g = frame[1]; 242 | mu_checkargs(mu_isfn(f) && mu_isfn(g), MU_COMP_KEY, 0xf, frame); 243 | 244 | frame[0] = mu_fn_comp(f, g); 245 | mu_dec(f); 246 | return 1; 247 | } 248 | 249 | MU_DEF_STR(mu_comp_key_def, "@") 250 | MU_DEF_BFN(mu_comp_def, 0x2, mu_comp_bfn) 251 | 252 | -------------------------------------------------------------------------------- /mu/buf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu bufs, opaque user buffers 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #ifndef MU_BUF_H 8 | #define MU_BUF_H 9 | #include "config.h" 10 | #include "types.h" 11 | 12 | 13 | // Definition of internal Mu buffers 14 | // 15 | // Each buffer is stored as a length and array of data. 16 | // Buffers can be mutated and used freely in C function, 17 | // but can't be accessed from Mu. 18 | struct mbuf { 19 | mref_t ref; // reference count 20 | mlen_t len; // length of allocated data 21 | mbyte_t data[]; // data follows 22 | // optional destructor stored at end 23 | }; 24 | 25 | // Destructor type for deallocating buffers 26 | typedef void mdtor_t(mu_t); 27 | 28 | 29 | // Creates buffer with specified size 30 | mu_t mu_buf_create(muint_t n); 31 | mu_t mu_buf_createdtor(muint_t n, mdtor_t *dtor); 32 | mu_t mu_buf_createtail(muint_t n, mdtor_t *dtor, mu_t tail); 33 | 34 | mu_inline mu_t mu_buf_fromdata(const void *s, muint_t n); 35 | mu_inline mu_t mu_buf_fromcstr(const char *s); 36 | mu_inline mu_t mu_buf_fromc(char s); 37 | mu_t mu_buf_frommu(mu_t s); 38 | 39 | // Buffer access 40 | mu_inline bool mu_isdtor(mu_t b, mdtor_t *dtor); 41 | 42 | mu_inline mlen_t mu_buf_getlen(mu_t b); 43 | mu_inline void *mu_buf_getdata(mu_t b); 44 | mu_inline mdtor_t *mu_buf_getdtor(mu_t b); 45 | mu_inline mu_t mu_buf_gettail(mu_t b); 46 | 47 | // Set destructor for a buffer 48 | void mu_buf_setdtor(mu_t *b, mdtor_t *dtor); 49 | void mu_buf_settail(mu_t *b, mu_t tail); 50 | 51 | // Support for read-only attribute access through tail 52 | mu_t mu_buf_lookup(mu_t b, mu_t k); 53 | 54 | // Formatting buffers with format strings 55 | mu_t mu_buf_vformat(const char *f, va_list args); 56 | mu_t mu_buf_format(const char *f, ...); 57 | 58 | // Resizes buffer by creating a copy 59 | void mu_buf_resize(mu_t *b, muint_t n); 60 | 61 | // Appending to buffers with amortized doubling 62 | void mu_buf_push(mu_t *b, muint_t *i, muint_t n); 63 | void mu_buf_pushdata(mu_t *b, muint_t *i, const void *s, muint_t n); 64 | mu_inline void mu_buf_pushcstr(mu_t *b, muint_t *i, const char *s); 65 | mu_inline void mu_buf_pushc(mu_t *b, muint_t *i, char s); 66 | void mu_buf_pushmu(mu_t *b, muint_t *i, mu_t s); 67 | void mu_buf_vpushf(mu_t *b, muint_t *i, const char *f, va_list args); 68 | void mu_buf_pushf(mu_t *b, muint_t *i, const char *fmt, ...); 69 | 70 | 71 | // Buffer creation functions 72 | mu_inline mu_t mu_buf_fromdata(const void *s, muint_t n) { 73 | mu_t b = mu_buf_create(n); 74 | memcpy(((struct mbuf *)(~7 & (muint_t)b))->data, s, n); 75 | return b; 76 | } 77 | 78 | mu_inline mu_t mu_buf_fromcstr(const char *s) { 79 | return mu_buf_fromdata(s, strlen(s)); 80 | } 81 | 82 | mu_inline mu_t mu_buf_fromc(char s) { 83 | return mu_buf_fromdata(&s, 1); 84 | } 85 | 86 | // Buffer access functions 87 | mu_inline bool mu_isdtor(mu_t b, mdtor_t *dtor) { 88 | if (mu_gettype(b) != MTDBUF) { 89 | return false; 90 | } 91 | 92 | struct mbuf *buf = (struct mbuf *)((muint_t)b - MTDBUF); 93 | return *(mdtor_t **)(buf->data + mu_align(buf->len)) == dtor; 94 | } 95 | 96 | mu_inline mlen_t mu_buf_getlen(mu_t b) { 97 | return ((struct mbuf *)(~7 & (muint_t)b))->len; 98 | } 99 | 100 | mu_inline void *mu_buf_getdata(mu_t b) { 101 | return ((struct mbuf *)(~7 & (muint_t)b))->data; 102 | } 103 | 104 | mu_inline mdtor_t *mu_buf_getdtor(mu_t b) { 105 | if ((MTDBUF^MTBUF) & (muint_t)b) { 106 | struct mbuf *buf = (struct mbuf *)((muint_t)b - MTDBUF); 107 | return *(mdtor_t **)(buf->data + mu_align(buf->len)); 108 | } else { 109 | return 0; 110 | } 111 | } 112 | 113 | mu_inline mu_t mu_buf_gettail(mu_t b) { 114 | if ((MTDBUF^MTBUF) & (muint_t)b) { 115 | struct mbuf *buf = (struct mbuf *)((muint_t)b - MTDBUF); 116 | return mu_inc(*(mu_t *)(buf->data + mu_align(buf->len) + 117 | sizeof(mdtor_t *))); 118 | } else { 119 | return 0; 120 | } 121 | } 122 | 123 | // Push functions 124 | mu_inline void mu_buf_pushcstr(mu_t *b, muint_t *i, const char *c) { 125 | mu_buf_pushdata(b, i, c, strlen(c)); 126 | } 127 | 128 | mu_inline void mu_buf_pushc(mu_t *b, muint_t *i, char c) { 129 | mu_buf_pushdata(b, i, &c, 1); 130 | } 131 | 132 | 133 | // Buffer macro for allocating buffers in global space 134 | #define _MU_DEF_BUF(name, cv, type, ...) \ 135 | mu_pure mu_t name(void) { \ 136 | typedef type t; \ 137 | static cv struct { \ 138 | mref_t ref; \ 139 | mlen_t len; \ 140 | t data[sizeof((t[])__VA_ARGS__) / sizeof(t)]; \ 141 | } inst = {0, sizeof((t[])__VA_ARGS__), __VA_ARGS__}; \ 142 | \ 143 | return (mu_t)((muint_t)&inst + MTBUF); \ 144 | } 145 | 146 | #define _MU_DEF_BUFDTOR(name, dtor, cv, type, ...) \ 147 | mu_pure mu_t name(void) { \ 148 | typedef type t; \ 149 | static cv struct { \ 150 | mref_t ref; \ 151 | mlen_t len; \ 152 | t data[sizeof((t[])__VA_ARGS__) / sizeof(t)]; \ 153 | mu_aligned(sizeof(muint_t)) mdtor_t *dtor; \ 154 | mu_aligned(sizeof(muint_t)) mu_t tail; \ 155 | } inst = {0, sizeof((t[])__VA_ARGS__), __VA_ARGS__, dtor, 0}; \ 156 | \ 157 | return (mu_t)((muint_t)&inst + MTDBUF); \ 158 | } 159 | 160 | #define _MU_DEF_BUFTAIL(name, dtor, tail, cv, type, ...) \ 161 | mu_pure mu_t name(void) { \ 162 | typedef type t; \ 163 | static mu_t ref = 0; \ 164 | static cv struct { \ 165 | mref_t ref; \ 166 | mlen_t len; \ 167 | t data[sizeof((t[])__VA_ARGS__) / sizeof(t)]; \ 168 | mu_aligned(sizeof(muint_t)) mdtor_t *dtor; \ 169 | mu_aligned(sizeof(muint_t)) mu_t tail; \ 170 | } inst = {0, sizeof((t[])__VA_ARGS__), __VA_ARGS__, dtor, 0}; \ 171 | \ 172 | if (!ref) { \ 173 | mu_t (*taildef)(void) = tail; \ 174 | if (taildef) { \ 175 | inst.tail = taildef(); \ 176 | } \ 177 | \ 178 | ref = (mu_t)((muint_t)&inst + MTDBUF); \ 179 | } \ 180 | \ 181 | return ref; \ 182 | } 183 | 184 | #define MU_DEF_BUF(name, type, ...) \ 185 | _MU_DEF_BUF(name, , type, __VA_ARGS__) 186 | 187 | #define MU_DEF_BUFDTOR(name, dtor, type, ...) \ 188 | _MU_DEF_BUFDTOR(name, dtor, , type, __VA_ARGS__) 189 | 190 | #define MU_DEF_BUFTAIL(name, dtor, tail, type, ...) \ 191 | _MU_DEF_BUFTAIL(name, dtor, tail, , type, __VA_ARGS__) 192 | 193 | #define MU_DEF_CONSTBUF(name, type, ...) \ 194 | _MU_DEF_BUF(name, const, type, __VA_ARGS__) 195 | 196 | #define MU_DEF_CONSTBUFDTOR(name, dtor, type, ...) \ 197 | _MU_DEF_BUFDTOR(name, dtor, const, type, __VA_ARGS__) 198 | 199 | #define MU_DEF_CONSTBUFTAIL(name, dtor, tail, type, ...) \ 200 | _MU_DEF_BUFTAIL(name, dtor, tail, , type, __VA_ARGS__) 201 | 202 | 203 | #endif 204 | -------------------------------------------------------------------------------- /mu/buf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu bufs, opaque user buffers 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #include "buf.h" 8 | #include "mu.h" 9 | 10 | 11 | // Buffer access 12 | mu_inline struct mbuf *mbuf(mu_t b) { 13 | return (struct mbuf *)((muint_t)b & ~7); 14 | } 15 | 16 | mu_inline bool mu_isdbuf(mu_t b) { 17 | return (MTBUF^MTDBUF) & (muint_t)b; 18 | } 19 | 20 | 21 | // Functions for handling buffers 22 | mu_t mu_buf_create(muint_t n) { 23 | return mu_buf_createtail(n, 0, 0); 24 | } 25 | 26 | mu_t mu_buf_createdtor(muint_t n, mdtor_t *dtor) { 27 | return mu_buf_createtail(n, dtor, 0); 28 | } 29 | 30 | mu_t mu_buf_createtail(muint_t n, mdtor_t *dtor, mu_t tail) { 31 | mu_checklen(n <= (mlen_t)-1, "buffer"); 32 | 33 | if (!dtor && !tail) { 34 | struct mbuf *b = mu_alloc(mu_offsetof(struct mbuf, data) + n); 35 | b->ref = 1; 36 | b->len = n; 37 | return (mu_t)((muint_t)b + MTBUF); 38 | } else { 39 | struct mbuf *b = mu_alloc(mu_offsetof(struct mbuf, data) + 40 | mu_align(n) + sizeof(dtor) + sizeof(tail)); 41 | b->ref = 1; 42 | b->len = n; 43 | *(mdtor_t **)(b->data + mu_align(b->len)) = dtor; 44 | *(mu_t *)(b->data + mu_align(b->len) + sizeof(mdtor_t *)) = tail; 45 | return (mu_t)((muint_t)b + MTDBUF); 46 | } 47 | } 48 | 49 | void mu_buf_destroy(mu_t b) { 50 | mu_dealloc(mbuf(b), mu_offsetof(struct mbuf, data) + mbuf(b)->len); 51 | } 52 | 53 | void mu_buf_destroydtor(mu_t b) { 54 | if (*(mdtor_t **)(mbuf(b)->data + mu_align(mbuf(b)->len))) { 55 | (*(mdtor_t **)(mbuf(b)->data + mu_align(mbuf(b)->len)))(b); 56 | } 57 | 58 | mu_dec(*(mu_t *)(mbuf(b)->data + 59 | mu_align(mbuf(b)->len) + sizeof(mdtor_t *))); 60 | mu_dealloc(mbuf(b), 61 | mu_offsetof(struct mbuf, data) + 62 | mu_align(mbuf(b)->len) + 63 | sizeof(mdtor_t *) + sizeof(mu_t)); 64 | } 65 | 66 | void mu_buf_resize(mu_t *b, muint_t n) { 67 | mu_checklen(n <= (mlen_t)-1, "buffer"); 68 | 69 | mu_t nb = mu_buf_createtail(n, mu_buf_getdtor(*b), mu_buf_gettail(*b)); 70 | memcpy(mu_buf_getdata(nb), mu_buf_getdata(*b), 71 | (n < mu_buf_getlen(*b)) ? n : mu_buf_getlen(*b)); 72 | 73 | mu_dec(*b); 74 | *b = nb; 75 | } 76 | 77 | void mu_buf_push(mu_t *b, muint_t *i, muint_t n) { 78 | n = *i + n; 79 | *i = n; 80 | 81 | if (mu_buf_getlen(*b) >= n) { 82 | return; 83 | } 84 | 85 | muint_t overhead = mu_offsetof(struct mbuf, data); 86 | if (mu_isdbuf(*b)) { 87 | overhead += sizeof(mdtor_t *) + sizeof(mu_t); 88 | } 89 | 90 | muint_t size = overhead + mu_buf_getlen(*b); 91 | if (size < MU_MINALLOC) { 92 | size = MU_MINALLOC; 93 | } 94 | 95 | while (size < overhead + n) { 96 | size <<= 1; 97 | } 98 | 99 | mu_buf_resize(b, size - overhead); 100 | } 101 | 102 | void mu_buf_setdtor(mu_t *b, mdtor_t *dtor) { 103 | if (!(mu_isdbuf(*b))) { 104 | mu_t nb = mu_buf_createdtor(mu_buf_getlen(*b), dtor); 105 | memcpy(mu_buf_getdata(nb), mu_buf_getdata(*b), mu_buf_getlen(nb)); 106 | 107 | mu_dec(*b); 108 | *b = nb; 109 | } else { 110 | *(mdtor_t **)(mbuf(*b)->data + mu_align(mbuf(*b)->len)) = dtor; 111 | } 112 | } 113 | 114 | void mu_buf_settail(mu_t *b, mu_t tail) { 115 | if (!(mu_isdbuf(*b))) { 116 | mu_t nb = mu_buf_createtail(mu_buf_getlen(*b), 0, tail); 117 | memcpy(mu_buf_getdata(nb), mu_buf_getdata(*b), mu_buf_getlen(nb)); 118 | 119 | mu_dec(*b); 120 | *b = nb; 121 | } else { 122 | *(mu_t *)(mbuf(*b)->data + mu_align(mbuf(*b)->len) + 123 | sizeof(mdtor_t *)) = tail; 124 | } 125 | } 126 | 127 | // Attribute access 128 | mu_t mu_buf_lookup(mu_t b, mu_t k) { 129 | if (!(mu_isdbuf(b))) { 130 | return 0; 131 | } 132 | 133 | mu_t tail = *(mu_t *)(mbuf(b)->data + mu_align(mbuf(b)->len) + 134 | sizeof(mdtor_t *)); 135 | if (!tail) { 136 | return 0; 137 | } 138 | 139 | return mu_tbl_lookup(tail, k); 140 | } 141 | 142 | // From functions 143 | mu_t mu_buf_frommu(mu_t m) { 144 | switch (mu_gettype(m)) { 145 | case MTNIL: 146 | return mu_buf_create(0); 147 | 148 | case MTSTR: 149 | case MTBUF: 150 | case MTDBUF: { 151 | mu_t b = mu_buf_fromdata(mbuf(m)->data, mbuf(m)->len); 152 | mu_dec(m); 153 | return b; 154 | } break; 155 | 156 | default: 157 | return mu_buf_format("%t", m); 158 | } 159 | } 160 | 161 | mu_t mu_buf_vformat(const char *f, va_list args) { 162 | mu_t b = mu_buf_create(0); 163 | muint_t n = 0; 164 | mu_buf_vpushf(&b, &n, f, args); 165 | 166 | if (mu_buf_getlen(b) != n) { 167 | mu_buf_resize(&b, n); 168 | } 169 | 170 | return b; 171 | } 172 | 173 | mu_t mu_buf_format(const char *f, ...) { 174 | va_list args; 175 | va_start(args, f); 176 | mu_t m = mu_str_vformat(f, args); 177 | va_end(args); 178 | return m; 179 | } 180 | 181 | // Concatenation functions with amortized doubling 182 | void mu_buf_pushdata(mu_t *b, muint_t *i, const void *c, muint_t n) { 183 | mu_buf_push(b, i, n); 184 | memcpy((mbyte_t *)mu_buf_getdata(*b) + *i - n, c, n); 185 | } 186 | 187 | void mu_buf_pushmu(mu_t *b, muint_t *i, mu_t c) { 188 | mu_assert(mu_isstr(c) || mu_isbuf(c)); 189 | mu_t cbuf = (mu_t)(~(MTSTR^MTBUF) & (muint_t)c); 190 | 191 | mu_buf_pushdata(b, i, mu_buf_getdata(cbuf), mu_buf_getlen(cbuf)); 192 | mu_dec(c); 193 | } 194 | 195 | 196 | // Buffer formatting 197 | static mbyte_t mu_buf_toascii(muint_t c) { 198 | return (c < 10) ? '0' + c : 'a' + (c-10); 199 | } 200 | 201 | static void mu_buf_append_unsigned(mu_t *b, muint_t *i, muint_t u) { 202 | if (u == 0) { 203 | mu_buf_pushc(b, i, '0'); 204 | return; 205 | } 206 | 207 | muint_t size = 0; 208 | muint_t u2 = u; 209 | while (u2 > 0) { 210 | size += 1; 211 | u2 /= 10; 212 | } 213 | 214 | mu_buf_push(b, i, size); 215 | 216 | char *c = (char *)mu_buf_getdata(*b) + *i - 1; 217 | while (u > 0) { 218 | *c = mu_buf_toascii(u % 10); 219 | u /= 10; 220 | c--; 221 | } 222 | } 223 | 224 | static void mu_buf_append_signed(mu_t *b, muint_t *i, mint_t d) { 225 | if (d < 0) { 226 | mu_buf_pushc(b, i, '-'); 227 | d = -d; 228 | } 229 | 230 | mu_buf_append_unsigned(b, i, d); 231 | } 232 | 233 | static void mu_buf_append_hex(mu_t *b, muint_t *i, muint_t x, int n) { 234 | n = n ? n : sizeof(unsigned); 235 | 236 | for (muint_t j = 0; j < 2*n; j++) { 237 | mu_buf_pushc(b, i, mu_buf_toascii((x >> 4*(2*n-j-1)) & 0xf)); 238 | } 239 | } 240 | 241 | MU_DEF_STR(mu_buf_key_def, "buf") 242 | static mu_t (*const mu_attr_names[8])(void) = { 243 | [MTNIL] = mu_kw_nil_def, 244 | [MTNUM] = mu_num_key_def, 245 | [MTSTR] = mu_str_key_def, 246 | [MTTBL] = mu_tbl_key_def, 247 | [MTRTBL] = mu_tbl_key_def, 248 | [MTFN] = mu_kw_fn_def, 249 | [MTBUF] = mu_buf_key_def, 250 | [MTDBUF] = mu_buf_key_def, 251 | }; 252 | 253 | #define mu_buf_va_uint(va, n) \ 254 | ((n <= sizeof(unsigned)) ? va_arg(va, unsigned) : va_arg(va, muint_t)) 255 | 256 | #define mu_buf_va_int(va, n) \ 257 | ((n <= sizeof(signed)) ? va_arg(va, signed) : va_arg(va, muint_t)) 258 | 259 | void mu_buf_vpushf(mu_t *b, muint_t *i, const char *f, va_list args) { 260 | while (*f) { 261 | if (*f != '%') { 262 | mu_buf_pushc(b, i, *f++); 263 | continue; 264 | } 265 | f++; 266 | 267 | int size = 0; 268 | switch (*f) { 269 | case 'w': f++; size = sizeof(muint_t); break; 270 | case 'h': f++; size = sizeof(muinth_t); break; 271 | case 'q': f++; size = sizeof(muintq_t); break; 272 | case 'b': f++; size = sizeof(mbyte_t); break; 273 | } 274 | 275 | switch (*f++) { 276 | case '%': { 277 | mu_buf_pushc(b, i, '%'); 278 | } break; 279 | 280 | case 'm': { 281 | mu_t m = va_arg(args, mu_t); 282 | mu_buf_pushmu(b, i, m); 283 | } break; 284 | 285 | case 'r': { 286 | mu_t m = va_arg(args, mu_t); 287 | m = mu_fn_call(MU_REPR, 0x21, m, mu_num_fromuint(0)); 288 | mu_buf_pushmu(b, i, m); 289 | } break; 290 | 291 | case 't': { 292 | mu_t m = va_arg(args, mu_t); 293 | mu_buf_pushf(b, i, "<%m 0x%wx>", 294 | mu_attr_names[mu_gettype(m)](), 295 | (muint_t)m & ~7); 296 | mu_dec(m); 297 | } break; 298 | 299 | case 'n': { 300 | const mbyte_t *s = va_arg(args, const mbyte_t *); 301 | muint_t n = mu_buf_va_uint(args, size); 302 | mu_buf_pushdata(b, i, s, n); 303 | } break; 304 | 305 | case 's': { 306 | const char *s = va_arg(args, const char *); 307 | mu_buf_pushdata(b, i, s, strlen(s)); 308 | } break; 309 | 310 | case 'u': { 311 | muint_t u = mu_buf_va_uint(args, size); 312 | mu_buf_append_unsigned(b, i, u); 313 | } break; 314 | 315 | case 'd': { 316 | mint_t d = mu_buf_va_int(args, size); 317 | mu_buf_append_signed(b, i, d); 318 | } break; 319 | 320 | case 'x': { 321 | muint_t u = mu_buf_va_uint(args, size); 322 | mu_buf_append_hex(b, i, u, size); 323 | } break; 324 | 325 | case 'c': { 326 | muint_t u = mu_buf_va_uint(args, size); 327 | mu_buf_pushc(b, i, u); 328 | } break; 329 | 330 | default: { 331 | mu_errorf("invalid format argument"); 332 | } break; 333 | } 334 | } 335 | } 336 | 337 | void mu_buf_pushf(mu_t *b, muint_t *i, const char *fmt, ...) { 338 | va_list args; 339 | va_start(args, fmt); 340 | mu_buf_vpushf(b, i, fmt, args); 341 | va_end(args); 342 | } 343 | 344 | -------------------------------------------------------------------------------- /dis/dis.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu virtual machine 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #include "dis.h" 8 | #include "mu/mu.h" 9 | 10 | 11 | // Disassemble bytecode for debugging and introspection 12 | // currently outputs to stdout 13 | static const char *const op_names[16] = { 14 | [MU_OP_IMM] = "imm", 15 | [MU_OP_FN] = "fn", 16 | [MU_OP_TBL] = "tbl", 17 | [MU_OP_MOVE] = "move", 18 | [MU_OP_DUP] = "dup", 19 | [MU_OP_DROP] = "drop", 20 | [MU_OP_LOOKUP] = "lookup", 21 | [MU_OP_LOOKDN] = "lookdn", 22 | [MU_OP_INSERT] = "insert", 23 | [MU_OP_ASSIGN] = "assign", 24 | [MU_OP_JUMP] = "jump", 25 | [MU_OP_JTRUE] = "jtrue", 26 | [MU_OP_JFALSE] = "jfalse", 27 | [MU_OP_CALL] = "call", 28 | [MU_OP_TCALL] = "tcall", 29 | [MU_OP_RET] = "ret", 30 | }; 31 | 32 | static mu_t mu_dis_summu(mu_t m) { 33 | mu_t b = mu_buf_create(0); 34 | muint_t n = 0; 35 | mu_buf_pushf(&b, &n, " (%r", m); 36 | if (n > 8+2) { 37 | n = 8; 38 | mu_buf_pushf(&b, &n, ".."); 39 | } 40 | mu_buf_pushf(&b, &n, ")"); 41 | mu_buf_resize(&b, n); 42 | return b; 43 | } 44 | 45 | static mu_t mu_dis_sumpair(mu_t k, mu_t v) { 46 | mu_t b = mu_buf_create(0); 47 | muint_t n = 0; 48 | mu_buf_pushf(&b, &n, " (%r", k); 49 | if (n > 8+2) { 50 | n = 8; 51 | mu_buf_pushf(&b, &n, ".."); 52 | } 53 | muint_t oldn = n; 54 | mu_buf_pushf(&b, &n, ": %r", v); 55 | if (n > oldn + 8+2) { 56 | n = oldn + 8; 57 | mu_buf_pushf(&b, &n, ".."); 58 | } 59 | mu_buf_pushf(&b, &n, ")"); 60 | mu_buf_resize(&b, n); 61 | return b; 62 | } 63 | 64 | static void mu_dis_code(mu_t c) { 65 | mu_t *imms = mu_code_getimms(c); 66 | const uint16_t *start = mu_code_getbcode(c); 67 | const uint16_t *pc = mu_code_getbcode(c); 68 | const uint16_t *end = pc + mu_code_getbcodelen(c)/2; 69 | 70 | mu_printf("regs: %qu, locals: %qu, args: 0x%bx", 71 | mu_code_getregs(c), 72 | mu_code_getlocals(c), 73 | mu_code_getargs(c)); 74 | 75 | if (mu_code_getimmslen(c) > 0) { 76 | mu_printf("imms:"); 77 | for (muint_t i = 0; i < mu_code_getimmslen(c); i++) { 78 | mu_printf("%hx %t%m", i, mu_inc(imms[i]), 79 | mu_dis_summu(mu_inc(imms[i]))); 80 | } 81 | } 82 | 83 | mu_printf("bcode:"); 84 | while (pc < end) { 85 | mop_t op = pc[0] >> 12; 86 | 87 | if (op == MU_OP_DROP) { 88 | mu_printf("%hx %bx%bx %s r%d", pc - start, 89 | pc[0] >> 8, 0xff & pc[0], op_names[op], 90 | 0xf & (pc[0] >> 8)); 91 | pc += 1; 92 | } else if (op >= MU_OP_RET && op <= MU_OP_DROP) { 93 | mu_printf("%hx %bx%bx %s r%d, 0x%bx", pc - start, 94 | pc[0] >> 8, 0xff & pc[0], op_names[op], 95 | 0xf & (pc[0] >> 8), 0xff & pc[0]); 96 | pc += 1; 97 | } else if (op >= MU_OP_LOOKDN && op <= MU_OP_ASSIGN) { 98 | mu_printf("%hx %bx%bx %s r%d, r%d[r%d]", pc - start, 99 | pc[0] >> 8, 0xff & pc[0], op_names[op], 100 | 0xf & (pc[0] >> 8), 0xf & (pc[0] >> 4), 0xf & pc[0]); 101 | pc += 1; 102 | } else if (op == MU_OP_IMM && (0xff & pc[0]) == 0xff) { 103 | mu_printf("%hx %bx%bx%bx%bx %s r%d, %u%m", pc - start, 104 | pc[0] >> 8, 0xff & pc[0], 105 | pc[1] >> 8, 0xff & pc[1], op_names[op], 106 | 0xf & (pc[0] >> 8), pc[1], 107 | mu_dis_summu(mu_inc(imms[pc[1]]))); 108 | pc += 2; 109 | } else if (op == MU_OP_IMM) { 110 | mu_printf("%hx %bx%bx %s r%d, %u%m", pc - start, 111 | pc[0] >> 8, 0xff & pc[0], op_names[op], 112 | 0xf & (pc[0] >> 8), 0x7f & pc[0], 113 | mu_dis_summu(mu_inc(imms[0x7f & pc[0]]))); 114 | pc += 1; 115 | } else if (op >= MU_OP_IMM && op <= MU_OP_TBL 116 | && (0xff & pc[0]) == 0xff) { 117 | mu_printf("%hx %bx%bx%bx%bx %s r%d, %u", pc - start, 118 | pc[0] >> 8, 0xff & pc[0], 119 | pc[1] >> 8, 0xff & pc[1], op_names[op], 120 | 0xf & (pc[0] >> 8), pc[1]); 121 | pc += 2; 122 | } else if (op >= MU_OP_IMM && op <= MU_OP_TBL) { 123 | mu_printf("%hx %bx%bx %s r%d, %u", pc - start, 124 | pc[0] >> 8, 0xff & pc[0], op_names[op], 125 | 0xf & (pc[0] >> 8), 0x7f & pc[0]); 126 | pc += 1; 127 | } else if (op >= MU_OP_JFALSE && op <= MU_OP_JUMP 128 | && (0xff & pc[0]) == 0xff) { 129 | mu_printf("%hx %bx%bx%bx%bx %s r%d, %d (%hx)", pc - start, 130 | pc[0] >> 8, 0xff & pc[0], 131 | pc[1] >> 8, 0xff & pc[1], op_names[op], 132 | 0xf & (pc[0] >> 8), (int16_t)pc[1], 133 | ((int16_t)pc[1]) + pc+2 - start); 134 | pc += 2; 135 | } else if (op >= MU_OP_JFALSE && op <= MU_OP_JUMP) { 136 | mu_printf("%hx %bx%bx %s r%d, %d (%hx)", pc - start, 137 | pc[0] >> 8, 0xff & pc[0], op_names[op], 138 | 0xf & (pc[0] >> 8), (int16_t)(pc[0] << 8) >> 8, 139 | ((int16_t)(pc[0] << 8) >> 8) + pc+1 - start); 140 | pc += 1; 141 | } 142 | } 143 | } 144 | 145 | static void mu_dis_bufdata(mu_t m) { 146 | mu_t line = mu_buf_create(80); 147 | muint_t maxwidth = 0; 148 | 149 | for (muint_t i = 0; i < mu_buf_getlen(m); i += 16) { 150 | muint_t n = 0; 151 | mu_buf_pushf(&line, &n, "%hx ", i); 152 | for (muint_t j = 0; j < 16 && i+j < mu_buf_getlen(m); j++) { 153 | mu_buf_pushf(&line, &n, "%bx ", 154 | ((mbyte_t *)mu_buf_getdata(m))[i+j]); 155 | } 156 | 157 | if (n > maxwidth) { 158 | maxwidth = n; 159 | } 160 | 161 | while (n < maxwidth+1) { 162 | mu_buf_pushf(&line, &n, " "); 163 | } 164 | 165 | for (muint_t j = 0; j < 16 && i+j < mu_buf_getlen(m); j++) { 166 | mbyte_t c = ((mbyte_t *)mu_buf_getdata(m))[i+j]; 167 | mu_buf_pushc(&line, &n, (c >= ' ' && c <= '~') ? c : '.'); 168 | } 169 | 170 | mu_print(mu_buf_getdata(line), n); 171 | } 172 | 173 | mu_dec(line); 174 | } 175 | 176 | static void mu_dis_num(mu_t m) { 177 | muint_t x = (muint_t)m; 178 | #ifdef MU64 179 | mu_printf("sign: %wx (%c1)", 180 | ((0x8000000000000000 & (muint_t)x)), 181 | ((0x8000000000000000 & (muint_t)x) >> 63) ? '-' : '+'); 182 | mu_printf("exp: %wx (2^%wd)", 183 | ((0x7ff0000000000000 & (muint_t)x)), 184 | ((0x7ff0000000000000 & (muint_t)x) >> 52) - 0x3ff); 185 | mu_printf("mant: %wx (%r)", 186 | ((0x000ffffffffffff8 & (muint_t)x)), 187 | ((0x000ffffffffffff8 & (muint_t)x)) | 0x3ff0000000000000 | MTNUM); 188 | #else 189 | mu_printf("sign: %wx (%c1)", 190 | ((0x80000000 & (muint_t)x)), 191 | ((0x80000000 & (muint_t)x) >> 31) ? '-' : '+'); 192 | mu_printf("exp: %wx (2^%wd)", 193 | ((0x7ff00000 & (muint_t)x)), 194 | ((0x7ff00000 & (muint_t)x) >> 23) - 0x7f); 195 | mu_printf("mant: %wx (%r)", 196 | ((0x007ffff8 & (muint_t)x)), 197 | ((0x007ffff8 & (muint_t)x)) | 0x7f000000 | MTNUM); 198 | #endif 199 | mu_printf("value: %r (%m)", m, mu_fn_call(MU_HEX, 0x11, m)); 200 | } 201 | 202 | static void mu_dis_str(mu_t m) { 203 | mu_printf("ref: %d, len: %d", mu_getref(m), mu_str_getlen(m)); 204 | mu_printf("data:"); 205 | mu_dis_bufdata(m); 206 | } 207 | 208 | static void mu_dis_buf(mu_t m) { 209 | mu_printf("ref: %d, len: %d", mu_getref(m), mu_buf_getlen(m)); 210 | mu_printf("dtor: 0x%wx", mu_buf_getdtor(m)); 211 | mu_printf("tail: %t", mu_buf_gettail(m)); 212 | mu_printf("data:"); 213 | mu_dis_bufdata(m); 214 | } 215 | 216 | static void mu_dis_tbl(mu_t m) { 217 | struct mtbl *t = (struct mtbl *)((muint_t)m & ~7); 218 | mu_printf("ref: %hu, len: %hu, nils: %hu", 219 | t->ref, t->len, t->nils); 220 | mu_printf("npw2: %qu, isize: %qu, ro: %d", 221 | t->npw2, t->isize, mu_gettype(m) == MTRTBL); 222 | mu_printf("tail: %t", mu_inc(t->tail)); 223 | 224 | if (t->isize == 0) { 225 | mu_printf("array:"); 226 | for (muint_t i = 0; i < t->len+t->nils; i++) { 227 | mu_printf("%hx %t%m", i, mu_inc(t->array[i]), 228 | mu_dis_summu(mu_inc(t->array[i]))); 229 | } 230 | } else { 231 | mu_printf("indices:"); 232 | mu_t line = mu_buf_create(80); 233 | for (muint_t i = 0; i < (1 << t->npw2); i += 16) { 234 | muint_t n = 0; 235 | mu_buf_pushf(&line, &n, "%hx ", i); 236 | for (muint_t j = 0; j < 16/t->isize && i+j < (1 << t->npw2); j++) { 237 | #ifdef MU64 238 | if (t->isize == 1) { 239 | mu_buf_pushf(&line, &n, "%bx ", ((mbyte_t*)t->array)[i+j]); 240 | } else if (t->isize == 2) { 241 | mu_buf_pushf(&line, &n, "%qx ", ((muintq_t*)t->array)[i+j]); 242 | } else if (t->isize == 4) { 243 | mu_buf_pushf(&line, &n, "%hx ", ((muinth_t*)t->array)[i+j]); 244 | } else if (t->isize == 8) { 245 | mu_buf_pushf(&line, &n, "%wx ", ((muint_t*)t->array)[i+j]); 246 | } 247 | #else 248 | if (t->isize == 1) { 249 | mu_buf_pushf(&line, &n, "%bx ", ((mbyte_t*)t->array)[i+j]); 250 | } else if (t->isize == 2) { 251 | mu_buf_pushf(&line, &n, "%hx ", ((muinth_t*)t->array)[i+j]); 252 | } else if (t->isize == 4) { 253 | mu_buf_pushf(&line, &n, "%wx ", ((muint_t*)t->array)[i+j]); 254 | } 255 | #endif 256 | } 257 | 258 | mu_print(mu_buf_getdata(line), n); 259 | } 260 | mu_dec(line); 261 | 262 | mu_printf("array:"); 263 | muint_t off = (t->isize*(1 << t->npw2) + 264 | (2*sizeof(mu_t))-1) / (2*sizeof(mu_t)); 265 | 266 | for (muint_t i = 0; i < t->len+t->nils; i++) { 267 | mu_printf("%hx %t %t%m", i, 268 | mu_inc(t->array[2*(off+i)+0]), 269 | mu_inc(t->array[2*(off+i)+1]), 270 | mu_dis_sumpair( 271 | mu_inc(t->array[2*(off+i)+0]), 272 | mu_inc(t->array[2*(off+i)+1]))); 273 | } 274 | } 275 | } 276 | 277 | static void mu_dis_fn(mu_t m) { 278 | struct mfn *f = (struct mfn *)((muint_t)m & ~7); 279 | mu_printf("ref: %hu, args: 0x%bx, weak: %d", 280 | f->ref, f->args, (MU_FN_WEAK & f->flags) == MU_FN_WEAK); 281 | mu_printf("closure: %t", mu_inc(f->closure)); 282 | 283 | if ((MU_FN_SCOPED & f->flags) && (MU_FN_BUILTIN & f->flags)) { 284 | mu_printf("sbfn: 0x%wx", f->fn.sbfn); 285 | } else if (MU_FN_BUILTIN & f->flags) { 286 | mu_printf("bfn: 0x%wx", f->fn.bfn); 287 | } else { 288 | mu_dis_code(f->fn.code); 289 | } 290 | } 291 | 292 | void mu_dis(mu_t m) { 293 | mu_printf("-- %t --", mu_inc(m)); 294 | switch (mu_gettype(m)) { 295 | case MTNIL: return; 296 | case MTNUM: mu_dis_num(m); return; 297 | case MTSTR: mu_dis_str(m); return; 298 | case MTBUF: 299 | case MTDBUF: mu_dis_buf(m); return; 300 | case MTTBL: 301 | case MTRTBL: mu_dis_tbl(m); return; 302 | case MTFN: mu_dis_fn(m); return; 303 | } 304 | } 305 | 306 | static mcnt_t mu_dis_bfn(mu_t *frame) { 307 | mu_dis(frame[0]); 308 | mu_dec(frame[0]); 309 | return 0; 310 | } 311 | 312 | MU_DEF_STR(mu_dis_key_def, "dis") 313 | MU_DEF_BFN(mu_dis_def, 0x1, mu_dis_bfn) 314 | MU_DEF_TBL(mu_dis_module_def, { 315 | { mu_dis_key_def, mu_dis_def }, 316 | }) 317 | -------------------------------------------------------------------------------- /mu/vm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu virtual machine 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #include "vm.h" 8 | #include "mu.h" 9 | 10 | 11 | // Bytecode errors 12 | #define mu_checkbcode(pred) \ 13 | ((pred) ? (void)0 : mu_errorbcode()) 14 | static mu_noreturn mu_errorbcode(void) { 15 | mu_errorf("exceeded bytecode limits"); 16 | } 17 | 18 | 19 | // Encode the specified opcode and return its size 20 | // Encode the specified opcode and return its size 21 | // Note: size of the jump opcodes currently can not change based on argument 22 | void mu_encode(void (*emit)(void *, mbyte_t), void *p, 23 | mop_t op, mint_t d, mint_t a, mint_t b) { 24 | union { 25 | uint16_t u16; 26 | uint8_t u8[2]; 27 | } ins; 28 | 29 | mu_checkbcode(op <= 0xf && d <= 0xf); 30 | ins.u16 = 0xf000 & (op << 12); 31 | ins.u16 |= 0x0f00 & (d << 8); 32 | 33 | if (op >= MU_OP_RET && op <= MU_OP_DROP) { 34 | mu_checkbcode(a <= 0xff); 35 | ins.u16 |= 0x00ff & a; 36 | emit(p, ins.u8[0]); 37 | emit(p, ins.u8[1]); 38 | } else if (op >= MU_OP_LOOKDN && op <= MU_OP_ASSIGN) { 39 | mu_checkbcode(a <= 0xf && b <= 0xf); 40 | ins.u16 |= 0x00f0 & (a << 4); 41 | ins.u16 |= 0x000f & b; 42 | emit(p, ins.u8[0]); 43 | emit(p, ins.u8[1]); 44 | } else if (op >= MU_OP_IMM && op <= MU_OP_TBL) { 45 | mu_checkbcode(a <= 0xffff); 46 | if (a > 0xfe) { 47 | ins.u16 |= 0x00ff; 48 | emit(p, ins.u8[0]); 49 | emit(p, ins.u8[1]); 50 | 51 | ins.u16 = a; 52 | emit(p, ins.u8[0]); 53 | emit(p, ins.u8[1]); 54 | } else { 55 | ins.u16 |= 0x00ff & a; 56 | emit(p, ins.u8[0]); 57 | emit(p, ins.u8[1]); 58 | } 59 | } else if (op >= MU_OP_JFALSE && op <= MU_OP_JUMP) { 60 | a = (a / 2) - 2; 61 | mu_checkbcode(a <= 0x7fff && a >= -0x8000); 62 | 63 | ins.u16 |= 0x00ff; 64 | emit(p, ins.u8[0]); 65 | emit(p, ins.u8[1]); 66 | 67 | ins.u16 = a; 68 | emit(p, ins.u8[0]); 69 | emit(p, ins.u8[1]); 70 | } 71 | } 72 | 73 | mint_t mu_patch(void *p, mint_t nj) { 74 | uint16_t *c = p; 75 | mu_assert((c[0] >> 12) >= MU_OP_JFALSE && (c[0] >> 12) <= MU_OP_JUMP); 76 | 77 | mint_t pj = c[1]; 78 | c[1] = (nj / 2) - 2; 79 | 80 | return pj; 81 | } 82 | 83 | 84 | // Virtual machine dispatch macros 85 | #ifdef MU_COMPUTED_GOTO 86 | #define VM_DISPATCH(pc) \ 87 | { static void *const vm_entry[16] = { \ 88 | [MU_OP_IMM] = &&VM_ENTRY_MU_OP_IMM, \ 89 | [MU_OP_FN] = &&VM_ENTRY_MU_OP_FN, \ 90 | [MU_OP_TBL] = &&VM_ENTRY_MU_OP_TBL, \ 91 | [MU_OP_MOVE] = &&VM_ENTRY_MU_OP_MOVE, \ 92 | [MU_OP_DUP] = &&VM_ENTRY_MU_OP_DUP, \ 93 | [MU_OP_DROP] = &&VM_ENTRY_MU_OP_DROP, \ 94 | [MU_OP_LOOKUP] = &&VM_ENTRY_MU_OP_LOOKUP, \ 95 | [MU_OP_LOOKDN] = &&VM_ENTRY_MU_OP_LOOKDN, \ 96 | [MU_OP_INSERT] = &&VM_ENTRY_MU_OP_INSERT, \ 97 | [MU_OP_ASSIGN] = &&VM_ENTRY_MU_OP_ASSIGN, \ 98 | [MU_OP_JUMP] = &&VM_ENTRY_MU_OP_JUMP, \ 99 | [MU_OP_JTRUE] = &&VM_ENTRY_MU_OP_JTRUE, \ 100 | [MU_OP_JFALSE] = &&VM_ENTRY_MU_OP_JFALSE, \ 101 | [MU_OP_CALL] = &&VM_ENTRY_MU_OP_CALL, \ 102 | [MU_OP_TCALL] = &&VM_ENTRY_MU_OP_TCALL, \ 103 | [MU_OP_RET] = &&VM_ENTRY_MU_OP_RET, \ 104 | }; \ 105 | \ 106 | while (1) { \ 107 | register uint16_t ins = *pc++; \ 108 | goto *vm_entry[ins >> 12]; 109 | #define VM_DISPATCH_END \ 110 | } \ 111 | mu_unreachable; \ 112 | } 113 | 114 | #define VM_ENTRY(op) \ 115 | VM_ENTRY_##op: { 116 | #define VM_ENTRY_END \ 117 | goto *vm_entry[*pc >> 4]; \ 118 | } 119 | #else 120 | #define VM_DISPATCH(pc) \ 121 | { \ 122 | while (1) { \ 123 | register uint16_t ins = *pc++; \ 124 | switch (ins >> 12) { 125 | #define VM_DISPATCH_END \ 126 | } \ 127 | } \ 128 | mu_unreachable; \ 129 | } 130 | 131 | #define VM_ENTRY(op) \ 132 | case op: { 133 | #define VM_ENTRY_END \ 134 | break; \ 135 | } 136 | #endif 137 | 138 | 139 | #define VM_ENTRY_DA(op, d, a) \ 140 | VM_ENTRY(op) \ 141 | mu_unused unsigned d = 0xf & (ins >> 8); \ 142 | mu_unused unsigned a = 0xff & ins; 143 | 144 | #define VM_ENTRY_DAB(op, d, a, b) \ 145 | VM_ENTRY(op) \ 146 | mu_unused unsigned d = 0xf & (ins >> 8); \ 147 | mu_unused unsigned a = 0xf & (ins >> 4); \ 148 | mu_unused unsigned b = 0xf & (ins >> 0); 149 | 150 | #define VM_ENTRY_DI(op, d, i) \ 151 | VM_ENTRY(op) \ 152 | mu_unused unsigned d = 0xf & (ins >> 8); \ 153 | mu_unused muint_t i = 0xff & ins; \ 154 | if (i == 0xff) { \ 155 | i = *pc++; \ 156 | } 157 | 158 | #define VM_ENTRY_DJ(op, d, j) \ 159 | VM_ENTRY(op) \ 160 | mu_unused unsigned d = 0xf & (ins >> 8); \ 161 | mu_unused mint_t j = (int16_t)(ins << 8) >> 8; \ 162 | if (j == -1) { \ 163 | j = (int16_t)*pc++; \ 164 | } 165 | 166 | 167 | 168 | mcnt_t mu_exec(mu_t c, mu_t scope, mu_t *frame) { 169 | mu_assert(mu_iscode(c)); 170 | 171 | // Allocate temporary variables 172 | const uint16_t *pc; 173 | mu_t *imms; 174 | 175 | reenter: 176 | { // Setup the registers and scope 177 | mu_t regs[mu_code_getregs(c)]; 178 | regs[0] = scope; 179 | mu_framemove(mu_code_getargs(c), ®s[1], frame); 180 | 181 | // Setup other state 182 | imms = mu_code_getimms(c); 183 | pc = mu_code_getbcode(c); 184 | 185 | // Enter main execution loop 186 | VM_DISPATCH(pc) 187 | VM_ENTRY_DI(MU_OP_IMM, d, i) 188 | regs[d] = mu_inc(imms[i]); 189 | VM_ENTRY_END 190 | 191 | VM_ENTRY_DI(MU_OP_FN, d, i) 192 | regs[d] = mu_fn_fromcode(mu_inc(imms[i]), mu_inc(regs[0])); 193 | VM_ENTRY_END 194 | 195 | VM_ENTRY_DI(MU_OP_TBL, d, i) 196 | regs[d] = mu_tbl_create(i); 197 | VM_ENTRY_END 198 | 199 | VM_ENTRY_DA(MU_OP_MOVE, d, a) 200 | regs[d] = regs[a]; 201 | VM_ENTRY_END 202 | 203 | VM_ENTRY_DA(MU_OP_DUP, d, a) 204 | regs[d] = mu_inc(regs[a]); 205 | VM_ENTRY_END 206 | 207 | VM_ENTRY_DA(MU_OP_DROP, d, a) 208 | mu_dec(regs[d]); 209 | VM_ENTRY_END 210 | 211 | VM_ENTRY_DAB(MU_OP_LOOKUP, d, a, b) 212 | if (mu_istbl(regs[a])) { 213 | regs[d] = mu_tbl_lookup(regs[a], regs[b]); 214 | } else if (mu_isbuf(regs[a])) { 215 | regs[d] = mu_buf_lookup(regs[a], regs[b]); 216 | } else { 217 | mu_errorf("unable to lookup %r in %r", regs[b], regs[a]); 218 | } 219 | VM_ENTRY_END 220 | 221 | VM_ENTRY_DAB(MU_OP_LOOKDN, d, a, b) 222 | mu_t scratch; 223 | if (mu_istbl(regs[a])) { 224 | scratch = mu_tbl_lookup(regs[a], regs[b]); 225 | } else if (mu_isbuf(regs[a])) { 226 | scratch = mu_buf_lookup(regs[a], regs[b]); 227 | } else { 228 | mu_errorf("unable to lookup %r in %r", regs[b], regs[a]); 229 | } 230 | 231 | mu_dec(regs[a]); 232 | regs[d] = scratch; 233 | VM_ENTRY_END 234 | 235 | VM_ENTRY_DAB(MU_OP_INSERT, d, a, b) 236 | if (!mu_istbl(regs[a])) { 237 | mu_errorf("unable to insert %r to %r in %r", 238 | regs[d], regs[b], regs[a]); 239 | } 240 | 241 | mu_tbl_insert(regs[a], regs[b], regs[d]); 242 | VM_ENTRY_END 243 | 244 | VM_ENTRY_DAB(MU_OP_ASSIGN, d, a, b) 245 | if (!mu_istbl(regs[a])) { 246 | mu_errorf("unable to assign %r to %r in %r", 247 | regs[d], regs[b], regs[a]); 248 | } 249 | 250 | mu_tbl_assign(regs[a], regs[b], regs[d]); 251 | VM_ENTRY_END 252 | 253 | VM_ENTRY_DJ(MU_OP_JUMP, d, j) 254 | pc += j; 255 | VM_ENTRY_END 256 | 257 | VM_ENTRY_DJ(MU_OP_JTRUE, d, j) 258 | if (regs[d]) { 259 | pc += j; 260 | } 261 | VM_ENTRY_END 262 | 263 | VM_ENTRY_DJ(MU_OP_JFALSE, d, j) 264 | if (!regs[d]) { 265 | pc += j; 266 | } 267 | VM_ENTRY_END 268 | 269 | VM_ENTRY_DA(MU_OP_CALL, d, a) 270 | if (!mu_isfn(regs[d])) { 271 | mu_errorf("unable to call %r", regs[d]); 272 | } 273 | 274 | mu_framemove(a >> 4, frame, ®s[d+1]); 275 | mu_fn_fcall(regs[d], a, frame); 276 | mu_dec(regs[d]); 277 | mu_framemove(0xf & a, ®s[d], frame); 278 | VM_ENTRY_END 279 | 280 | VM_ENTRY_DA(MU_OP_RET, d, a) 281 | mu_framemove(a, frame, ®s[d]); 282 | mu_dec(scope); 283 | mu_dec(c); 284 | return a; 285 | VM_ENTRY_END 286 | 287 | VM_ENTRY_DA(MU_OP_TCALL, d, a) 288 | mu_t scratch = regs[d]; 289 | mu_framemove(a, frame, ®s[d+1]); 290 | mu_dec(scope); 291 | mu_dec(c); 292 | 293 | // Use a direct goto to garuntee a tail call when the target 294 | // is another mu function. Otherwise, we just try our hardest 295 | // to get a tail call emitted. 296 | if (!mu_isfn(scratch)) { 297 | mu_errorf("unable to call %r", scratch); 298 | } 299 | 300 | c = mu_fn_getcode(scratch); 301 | if (c) { 302 | mu_frameconvert(a, mu_code_getargs(c), frame); 303 | scope = mu_tbl_create(mu_code_getlocals(c)); 304 | mu_tbl_settail(scope, mu_fn_getclosure(scratch)); 305 | mu_dec(scratch); 306 | goto reenter; 307 | } else { 308 | return mu_fn_tcall(scratch, a, frame); 309 | } 310 | VM_ENTRY_END 311 | VM_DISPATCH_END 312 | } 313 | } 314 | 315 | -------------------------------------------------------------------------------- /repl/repl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu repl library for presenting a user-interactive interface 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #include "repl.h" 8 | 9 | 10 | #if MU_USE_STD_TERM 11 | // tie into unistd stuff 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | static bool registered = false; 19 | static struct termios termorig; 20 | 21 | int mu_sys_termenter(void) { 22 | if (tcgetattr(0, &termorig)) { 23 | mu_errorf("termios error: %d", errno); 24 | } 25 | 26 | if (!registered) { 27 | atexit(mu_sys_termexit); 28 | registered = true; 29 | } 30 | 31 | static struct termios termnew; 32 | termnew = termorig; 33 | termnew.c_lflag &= ~ICANON & ~ECHO; 34 | 35 | if (tcsetattr(0, TCSANOW, &termnew)) { 36 | mu_errorf("termios error: %d", errno); 37 | } 38 | 39 | return 0; 40 | } 41 | 42 | void mu_sys_termexit(void) { 43 | if (tcsetattr(0, TCSANOW, &termorig)) { 44 | mu_errorf("termios error: %d", errno); 45 | } 46 | } 47 | 48 | mint_t mu_sys_termread(void *buf, muint_t n) { 49 | return read(STDIN_FILENO, buf, n); 50 | } 51 | 52 | mint_t mu_sys_termwrite(const void *buf, muint_t n) { 53 | return write(STDOUT_FILENO, buf, n); 54 | } 55 | 56 | #endif 57 | 58 | 59 | // sys wrappers for repl 60 | static char mu_repl_getc(void) { 61 | char b; 62 | if (mu_sys_termread(&b, 1) < 0) { 63 | mu_errorf("read error: %d", errno); 64 | } 65 | 66 | return b; 67 | } 68 | 69 | static void mu_repl_write(const void *buf, size_t n) { 70 | if (mu_sys_termwrite(buf, n) < 0) { 71 | mu_errorf("write error: %d", errno); 72 | } 73 | } 74 | 75 | struct mrepl { 76 | mu_t line; 77 | muint_t n; 78 | 79 | int pos; 80 | int off; 81 | int cols; 82 | bool compat; 83 | 84 | int hpos; 85 | mu_t disp; 86 | const char *prompt; 87 | }; 88 | 89 | static mu_t mu_repl_history = MU_NIL; 90 | 91 | static void mu_repl_edit(struct mrepl *r) { 92 | if (r->hpos == -1) { 93 | return; 94 | } 95 | 96 | r->n = 0; 97 | mu_buf_pushmu(&r->line, &r->n, 98 | mu_tbl_lookup(mu_repl_history, 99 | mu_num_fromuint(r->hpos))); 100 | r->hpos = -1; 101 | } 102 | 103 | static void mu_repl_update(struct mrepl *r) { 104 | mu_t line; 105 | int linesize; 106 | if (r->hpos == -1) { 107 | line = mu_inc(r->line); 108 | linesize = r->n; 109 | } else { 110 | line = mu_tbl_lookup(mu_repl_history, 111 | mu_num_fromuint(r->hpos)); 112 | linesize = mu_buf_getlen(line); 113 | } 114 | 115 | if (r->pos > linesize) { 116 | r->pos = linesize; 117 | } else if (r->pos < 0) { 118 | r->pos = 0; 119 | } 120 | 121 | int plen = strlen(r->prompt); 122 | if (r->pos - r->off > r->cols - plen - 1) { 123 | r->off = r->pos - (r->cols - plen - 1); 124 | } else if (r->pos - r->off < 0) { 125 | r->off = r->pos; 126 | } 127 | 128 | linesize -= r->off; 129 | if (linesize > r->cols - plen) { 130 | linesize = r->cols - plen; 131 | } 132 | 133 | muint_t n = 0; 134 | mu_buf_pushf(&r->disp, &n, 135 | "\r\x1b[K%s%s%s%n\r\x1b[%dC", 136 | r->compat ? "\x1b[32m" : "", 137 | r->prompt, 138 | r->compat ? "\x1b[m" : "", 139 | (mbyte_t *)mu_buf_getdata(line) + r->off, 140 | linesize, 141 | r->pos - r->off + plen); 142 | mu_repl_write(mu_buf_getdata(r->disp), n); 143 | mu_dec(line); 144 | } 145 | 146 | static bool mu_repl_istabable(char c) { 147 | return ( 148 | (c >= 'a' && c <= 'z') || 149 | (c >= 'A' && c <= 'Z') || 150 | (c >= '0' && c <= '0') || 151 | c == '.' || c == '_'); 152 | } 153 | 154 | static void mu_repl_tab(struct mrepl *r, mu_t scope, bool show) { 155 | const char *data = mu_buf_getdata(r->line); 156 | muint_t prefix = 0; 157 | while (prefix < r->pos && mu_repl_istabable(data[r->pos-1-prefix])) { 158 | prefix++; 159 | } 160 | 161 | while (true) { 162 | muint_t j = 0; 163 | while (j < prefix && data[r->pos-prefix+j] != '.') { 164 | j++; 165 | } 166 | 167 | if (j == prefix) { 168 | break; 169 | } 170 | 171 | mu_t word = mu_str_fromdata(&data[r->pos-prefix], j); 172 | mu_t next = mu_tbl_lookup(scope, word); 173 | mu_dec(scope); 174 | if (!next || !mu_istbl(next)) { 175 | mu_dec(next); 176 | return; 177 | } 178 | 179 | scope = next; 180 | prefix -= j+1; 181 | } 182 | 183 | mu_t best = MU_NIL; 184 | mu_t results; 185 | if (show) { 186 | results = mu_tbl_create(0); 187 | } 188 | 189 | while (scope) { 190 | mu_t k; 191 | for (muint_t i = 0; mu_tbl_next(scope, &i, &k, NULL);) { 192 | if (!mu_isstr(k) || prefix > mu_str_getlen(k) || 193 | memcmp(&data[r->pos-prefix], mu_str_getdata(k), prefix) != 0) { 194 | mu_dec(k); 195 | continue; 196 | } 197 | 198 | if (show) { 199 | mu_tbl_push(results, mu_inc(k), mu_tbl_getlen(results)); 200 | } 201 | 202 | if (!best) { 203 | best = k; 204 | } else { 205 | muint_t i = 0; 206 | for (; i < mu_str_getlen(best); i++) { 207 | if (((mbyte_t*)mu_str_getdata(best))[i] != 208 | ((mbyte_t*)mu_str_getdata(k))[i]) { 209 | break; 210 | } 211 | } 212 | 213 | best = mu_fn_call(MU_SUBSET, 0x31, best, 214 | mu_num_fromuint(0), mu_num_fromuint(i)); 215 | mu_dec(k); 216 | } 217 | } 218 | 219 | mu_t tail = mu_tbl_gettail(scope); 220 | mu_dec(scope); 221 | scope = tail; 222 | } 223 | 224 | if (show) { 225 | mu_repl_write("\n", 1); 226 | int maxwidth = 0; 227 | mu_t v; 228 | for (muint_t i = 0; mu_tbl_next(results, &i, NULL, &v);) { 229 | if (mu_str_getlen(v) > maxwidth) { 230 | maxwidth = mu_str_getlen(v); 231 | } 232 | mu_dec(v); 233 | } 234 | 235 | int cols = r->cols / (maxwidth+2); 236 | int rows = (mu_tbl_getlen(results)+cols-1) / cols; 237 | for (muint_t i = 0; i < rows; i++) { 238 | for (muint_t j = 0; j < cols && 239 | j*rows + i < mu_tbl_getlen(results); j++) { 240 | mu_t s = mu_fn_call(MU_PAD, 0x21, 241 | mu_tbl_lookup(results, mu_num_fromuint(j*rows + i)), 242 | mu_num_fromuint(maxwidth+2)); 243 | mu_repl_write(mu_str_getdata(s), mu_str_getlen(s)); 244 | mu_dec(s); 245 | } 246 | 247 | mu_repl_write("\n", 1); 248 | } 249 | 250 | mu_dec(results); 251 | } 252 | 253 | if (best) { 254 | int diff = mu_str_getlen(best) - prefix; 255 | mu_buf_push(&r->line, &r->n, diff); 256 | memmove((mbyte_t*)mu_buf_getdata(r->line) + r->pos + diff, 257 | (mbyte_t*)mu_buf_getdata(r->line) + r->pos, 258 | r->n-diff - r->pos); 259 | memcpy((mbyte_t*)mu_buf_getdata(r->line) + r->pos, 260 | (const mbyte_t*)mu_str_getdata(best) + prefix, diff); 261 | mu_dec(best); 262 | r->pos += diff; 263 | } 264 | } 265 | 266 | mu_t mu_repl_read(const char *prompt, mu_t scope) { 267 | if (!mu_repl_history) { 268 | mu_repl_history = mu_tbl_create(0); 269 | } 270 | 271 | struct mrepl r = { 272 | .line = mu_buf_create(0), 273 | .n = 0, 274 | .pos = 0, 275 | .off = 0, 276 | .cols = 4096, 277 | .compat = false, 278 | .hpos = -1, 279 | .disp = mu_buf_create(0), 280 | .prompt = prompt, 281 | }; 282 | 283 | int err = mu_sys_termenter(); 284 | if (err) { 285 | mu_errorf("termenter failed: %d", err); 286 | } 287 | 288 | // just move cursor to end to find width, also checks if escape codes 289 | // work. parsing is left up to the main loop. 290 | mu_repl_write("\x1b[4096C\x1b[6n\r", 12); 291 | 292 | char c; 293 | char prev; 294 | 295 | while (1) { 296 | mu_repl_update(&r); 297 | 298 | prev = c; 299 | c = mu_repl_getc(); 300 | 301 | if (c == '\x0a') { // enter 302 | mu_repl_edit(&r); 303 | break; 304 | } else if (c == '\t') { // tab 305 | mu_repl_tab(&r, mu_inc(scope), prev == '\t'); 306 | } else if (c == '\x7f') { // backspace 307 | mu_repl_edit(&r); 308 | if (r.pos > 0) { 309 | memmove((mbyte_t*)mu_buf_getdata(r.line) + r.pos - 1, 310 | (mbyte_t*)mu_buf_getdata(r.line) + r.pos, 311 | r.n - r.pos); 312 | r.n -= 1; 313 | r.pos -= 1; 314 | } 315 | } else if (c == '\x1b') { // escape code 316 | c = mu_repl_getc(); 317 | if (c != '[') continue; 318 | 319 | c = mu_repl_getc(); 320 | if (c == 'D') { // left 321 | r.pos -= 1; 322 | } else if (c == 'C') { // right 323 | r.pos += 1; 324 | } else if (c == 'A') { // up 325 | mu_t h = mu_tbl_lookup(mu_repl_history, 326 | mu_num_fromuint(r.hpos + 1)); 327 | if (h) { 328 | r.hpos += 1; 329 | r.pos = mu_buf_getlen(h); 330 | mu_dec(h); 331 | } 332 | } else if (c == 'B') { // down 333 | if (r.hpos == 0) { 334 | r.hpos = -1; 335 | r.pos = r.n; 336 | } else { 337 | mu_t h = mu_tbl_lookup(mu_repl_history, 338 | mu_num_fromuint(r.hpos - 1)); 339 | if (h) { 340 | r.hpos -= 1; 341 | r.pos = mu_buf_getlen(h); 342 | mu_dec(h); 343 | } 344 | } 345 | } else if (c >= '0' && c <= '9') { 346 | // special codes 347 | int code; 348 | while (true) { 349 | code = 0; 350 | while (c >= '0' && c <= '9') { 351 | code = code*10 + (c - '0'); 352 | c = mu_repl_getc(); 353 | } 354 | 355 | if (c != ';') { 356 | break; 357 | } 358 | 359 | c = mu_repl_getc(); 360 | } 361 | 362 | if (c == 'R') { // terminal size 363 | r.cols = code; 364 | r.compat = true; 365 | } else if (code == 1) { // home 366 | r.pos = 0; 367 | } else if (code == 4) { // end 368 | r.pos = 4096; 369 | } else if (code == 3) { // delete 370 | mu_repl_edit(&r); 371 | if (r.pos < r.n) { 372 | memmove((mbyte_t*)mu_buf_getdata(r.line) + r.pos, 373 | (mbyte_t*)mu_buf_getdata(r.line) + r.pos + 1, 374 | r.n - r.pos); 375 | r.n -= 1; 376 | } 377 | } 378 | } 379 | } else { 380 | mu_repl_edit(&r); 381 | mu_buf_push(&r.line, &r.n, 1); 382 | memmove((mbyte_t*)mu_buf_getdata(r.line) + r.pos + 1, 383 | (mbyte_t*)mu_buf_getdata(r.line) + r.pos, 384 | r.n-1 - r.pos); 385 | ((mbyte_t*)mu_buf_getdata(r.line))[r.pos] = c; 386 | r.pos += 1; 387 | } 388 | } 389 | 390 | mu_repl_write("\n", 1); 391 | mu_sys_termexit(); 392 | mu_dec(r.disp); 393 | mu_buf_resize(&r.line, r.n); 394 | 395 | mu_tbl_insert(mu_repl_history, mu_num_fromuint(MU_REPL_HISTORY), 0); 396 | mu_tbl_push(mu_repl_history, mu_inc(r.line), 0); 397 | 398 | return r.line; 399 | } 400 | 401 | void mu_repl_feval(const char *prompt, 402 | mu_t scope, mcnt_t fc, mu_t *frame) { 403 | mu_t line = mu_repl_read(prompt, scope); 404 | mu_t c = mu_compile(mu_buf_getdata(line), 405 | mu_buf_getlen(line), mu_inc(scope)); 406 | mcnt_t rets = mu_exec(c, mu_inc(scope), frame); 407 | mu_frameconvert(rets, fc, frame); 408 | } 409 | 410 | mu_t mu_repl_veval(const char *prompt, 411 | mu_t scope, mcnt_t fc, va_list args) { 412 | mu_t frame[MU_FRAME]; 413 | 414 | mu_repl_feval(prompt, scope, fc, frame); 415 | 416 | for (muint_t i = 1; i < mu_framecount(fc); i++) { 417 | *va_arg(args, mu_t *) = frame[i]; 418 | } 419 | 420 | return fc ? *frame : 0; 421 | } 422 | 423 | mu_t mu_repl_eval(const char *prompt, 424 | mu_t scope, mcnt_t fc, ...) { 425 | va_list args; 426 | va_start(args, fc); 427 | mu_t ret = mu_repl_veval(prompt, scope, fc, args); 428 | va_end(args); 429 | return ret; 430 | } 431 | 432 | void mu_repl(const char *prompt, mu_t scope) { 433 | mu_t frame[MU_FRAME]; 434 | 435 | mu_repl_feval(prompt, scope, 0xf, frame); 436 | 437 | if (mu_tbl_getlen(frame[0]) > 0) { 438 | frame[1] = mu_num_fromuint(2); 439 | mu_fn_fcall(MU_REPR, 0x21, frame); 440 | 441 | mu_print((const char *)mu_str_getdata(frame[0]) + 1, 442 | mu_str_getlen(frame[0])-2); 443 | } 444 | 445 | mu_dec(frame[0]); 446 | } 447 | -------------------------------------------------------------------------------- /mu/mu.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The Mu scripting language 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a 7 | * copy of this software and associated documentation files (the "Software"), 8 | * to deal in the Software without restriction, including without limitation 9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | * and/or sell copies of the Software, and to permit persons to whom the 11 | * Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | * DEALINGS IN THE SOFTWARE. 23 | */ 24 | #ifndef MU_H 25 | #define MU_H 26 | #include "config.h" 27 | #include "types.h" 28 | #include "sys.h" 29 | #include "num.h" 30 | #include "buf.h" 31 | #include "str.h" 32 | #include "tbl.h" 33 | #include "fn.h" 34 | #include "parse.h" 35 | #include "vm.h" 36 | 37 | 38 | // Manual memory management 39 | // simple wrapper over malloc and free if available 40 | // returns 0 when size == 0 41 | void *mu_alloc(muint_t size); 42 | void mu_dealloc(void *, muint_t size); 43 | 44 | // System operations 45 | mu_noreturn mu_verrorf(const char *f, va_list args); 46 | mu_noreturn mu_errorf(const char *f, ...); 47 | mu_noreturn mu_error(const char *s, muint_t n); 48 | 49 | void mu_vprintf(const char *f, va_list args); 50 | void mu_printf(const char *f, ...); 51 | void mu_print(const char *s, muint_t n); 52 | 53 | mu_t mu_import(mu_t name); 54 | 55 | // Evaluation and entry into Mu 56 | void mu_feval(const char *s, muint_t n, mu_t scope, mcnt_t fc, mu_t *frame); 57 | mu_t mu_veval(const char *s, muint_t n, mu_t scope, mcnt_t fc, va_list args); 58 | mu_t mu_eval(const char *s, muint_t n, mu_t scope, mcnt_t fc, ...); 59 | 60 | // Checks for various conditions 61 | // using a macro here helps pathing and avoids cost of pushing args 62 | #define mu_checkargs(pred, ...) \ 63 | ((pred) ? (void)0 : mu_errorargs(__VA_ARGS__)) 64 | mu_noreturn mu_errorargs(mu_t name, mcnt_t fc, mu_t *frame); 65 | #define mu_checkconst(pred, ...) \ 66 | ((pred) ? (void)0 : mu_errorro(__VA_ARGS__)) 67 | mu_noreturn mu_errorro(const char *name); 68 | #define mu_checklen(pred, ...) \ 69 | ((pred) ? (void)0 : mu_errorlen(__VA_ARGS__)) 70 | mu_noreturn mu_errorlen(const char *name); 71 | 72 | // Declaration of mu constants, requires other MU_DEF_* for definition 73 | #define MU_DEF(name) \ 74 | extern mu_pure mu_t name(void); 75 | 76 | 77 | // Standard functions in readonly builtins table 78 | #define MU_BUILTINS mu_builtins_def() 79 | 80 | // Builtin constants 81 | #define MU_NIL ((mu_t)0) 82 | 83 | #define MU_TRUE mu_true_def() 84 | #define MU_FALSE MU_NIL 85 | 86 | #define MU_INF mu_inf_def() 87 | #define MU_NINF mu_ninf_def() 88 | #define MU_E mu_e_def() 89 | #define MU_PI mu_pi_def() 90 | 91 | // Builtin functions 92 | #define MU_NUM mu_num_def() 93 | #define MU_STR mu_str_def() 94 | #define MU_TBL mu_tbl_def() 95 | #define MU_FN mu_fn_def() 96 | 97 | #define MU_NOT mu_not_def() 98 | #define MU_EQ mu_eq_def() 99 | #define MU_NEQ mu_neq_def() 100 | #define MU_IS mu_is_def() 101 | #define MU_LT mu_lt_def() 102 | #define MU_LTE mu_lte_def() 103 | #define MU_GT mu_gt_def() 104 | #define MU_GTE mu_gte_def() 105 | 106 | #define MU_ADD mu_add_def() 107 | #define MU_SUB mu_sub_def() 108 | #define MU_MUL mu_mul_def() 109 | #define MU_DIV mu_div_def() 110 | #define MU_IDIV mu_idiv_def() 111 | #define MU_MOD mu_mod_def() 112 | #define MU_POW mu_pow_def() 113 | #define MU_LOG mu_log_def() 114 | #define MU_ABS mu_abs_def() 115 | #define MU_FLOOR mu_floor_def() 116 | #define MU_CEIL mu_ceil_def() 117 | 118 | #define MU_COS mu_cos_def() 119 | #define MU_ACOS mu_acos_def() 120 | #define MU_SIN mu_sin_def() 121 | #define MU_ASIN mu_asin_def() 122 | #define MU_TAN mu_tan_def() 123 | #define MU_ATAN mu_atan_def() 124 | 125 | #define MU_AND mu_and_def() 126 | #define MU_OR mu_or_def() 127 | #define MU_XOR mu_xor_def() 128 | #define MU_DIFF mu_diff_def() 129 | #define MU_SHL mu_shl_def() 130 | #define MU_SHR mu_shr_def() 131 | 132 | #define MU_PARSE mu_parse_def() 133 | #define MU_REPR mu_repr_def() 134 | #define MU_ORD mu_ord_def() 135 | #define MU_CHR mu_chr_def() 136 | #define MU_BIN mu_bin_def() 137 | #define MU_OCT mu_oct_def() 138 | #define MU_HEX mu_hex_def() 139 | 140 | #define MU_LEN mu_len_def() 141 | #define MU_TAIL mu_tail_def() 142 | #define MU_CONST mu_const_def() 143 | #define MU_PUSH mu_push_def() 144 | #define MU_POP mu_pop_def() 145 | #define MU_CONCAT mu_concat_def() 146 | #define MU_SUBSET mu_subset_def() 147 | 148 | #define MU_FIND mu_find_def() 149 | #define MU_REPLACE mu_replace_def() 150 | #define MU_SPLIT mu_split_def() 151 | #define MU_JOIN mu_join_def() 152 | #define MU_PAD mu_pad_def() 153 | #define MU_STRIP mu_strip_def() 154 | 155 | #define MU_BIND mu_bind_def() 156 | #define MU_COMP mu_comp_def() 157 | #define MU_MAP mu_map_def() 158 | #define MU_FILTER mu_filter_def() 159 | #define MU_REDUCE mu_reduce_def() 160 | #define MU_ANY mu_any_def() 161 | #define MU_ALL mu_all_def() 162 | 163 | #define MU_ITER mu_iter_def() 164 | #define MU_PAIRS mu_pairs_def() 165 | #define MU_RANGE mu_range_def() 166 | #define MU_REPEAT mu_repeat_def() 167 | #define MU_RANDOM mu_random_def() 168 | 169 | #define MU_ZIP mu_zip_def() 170 | #define MU_CHAIN mu_chain_def() 171 | #define MU_TAKE mu_take_def() 172 | #define MU_DROP mu_drop_def() 173 | 174 | #define MU_MIN mu_min_def() 175 | #define MU_MAX mu_max_def() 176 | #define MU_REVERSE mu_reverse_def() 177 | #define MU_SORT mu_sort_def() 178 | 179 | #define MU_ERROR mu_error_def() 180 | #define MU_PRINT mu_print_def() 181 | #define MU_IMPORT mu_import_def() 182 | 183 | // Builtin keys 184 | #define MU_TRUE_KEY mu_true_key_def() 185 | #define MU_FALSE_KEY mu_false_key_def() 186 | #define MU_INF_KEY mu_inf_key_def() 187 | #define MU_E_KEY mu_e_key_def() 188 | #define MU_PI_KEY mu_pi_key_def() 189 | 190 | #define MU_NUM_KEY mu_num_key_def() 191 | #define MU_STR_KEY mu_str_key_def() 192 | #define MU_TBL_KEY mu_tbl_key_def() 193 | #define MU_FN_KEY mu_fn_key_def() 194 | 195 | #define MU_NOT_KEY mu_not_key_def() 196 | #define MU_EQ_KEY mu_eq_key_def() 197 | #define MU_NEQ_KEY mu_neq_key_def() 198 | #define MU_IS_KEY mu_is_key_def() 199 | #define MU_LT_KEY mu_lt_key_def() 200 | #define MU_LTE_KEY mu_lte_key_def() 201 | #define MU_GT_KEY mu_gt_key_def() 202 | #define MU_GTE_KEY mu_gte_key_def() 203 | 204 | #define MU_ADD_KEY mu_add_key_def() 205 | #define MU_SUB_KEY mu_sub_key_def() 206 | #define MU_MUL_KEY mu_mul_key_def() 207 | #define MU_DIV_KEY mu_div_key_def() 208 | #define MU_ABS_KEY mu_abs_key_def() 209 | #define MU_FLOOR_KEY mu_floor_key_def() 210 | #define MU_CEIL_KEY mu_ceil_key_def() 211 | #define MU_IDIV_KEY mu_idiv_key_def() 212 | #define MU_MOD_KEY mu_mod_key_def() 213 | #define MU_POW_KEY mu_pow_key_def() 214 | #define MU_LOG_KEY mu_log_key_def() 215 | 216 | #define MU_COS_KEY mu_cos_key_def() 217 | #define MU_ACOS_KEY mu_acos_key_def() 218 | #define MU_SIN_KEY mu_sin_key_def() 219 | #define MU_ASIN_KEY mu_asin_key_def() 220 | #define MU_TAN_KEY mu_tan_key_def() 221 | #define MU_ATAN_KEY mu_atan_key_def() 222 | 223 | #define MU_AND_KEY mu_and_key_def() 224 | #define MU_OR_KEY mu_or_key_def() 225 | #define MU_XOR_KEY mu_xor_key_def() 226 | #define MU_DIFF_KEY mu_diff_key_def() 227 | #define MU_SHL_KEY mu_shl_key_def() 228 | #define MU_SHR_KEY mu_shr_key_def() 229 | 230 | #define MU_PARSE_KEY mu_parse_key_def() 231 | #define MU_REPR_KEY mu_repr_key_def() 232 | #define MU_ORD_KEY mu_ord_key_def() 233 | #define MU_CHR_KEY mu_chr_key_def() 234 | #define MU_BIN_KEY mu_bin_key_def() 235 | #define MU_OCT_KEY mu_oct_key_def() 236 | #define MU_HEX_KEY mu_hex_key_def() 237 | 238 | #define MU_LEN_KEY mu_len_key_def() 239 | #define MU_TAIL_KEY mu_tail_key_def() 240 | #define MU_CONST_KEY mu_const_key_def() 241 | #define MU_PUSH_KEY mu_push_key_def() 242 | #define MU_POP_KEY mu_pop_key_def() 243 | #define MU_CONCAT_KEY mu_concat_key_def() 244 | #define MU_SUBSET_KEY mu_subset_key_def() 245 | 246 | #define MU_FIND_KEY mu_find_key_def() 247 | #define MU_REPLACE_KEY mu_replace_key_def() 248 | #define MU_SPLIT_KEY mu_split_key_def() 249 | #define MU_JOIN_KEY mu_join_key_def() 250 | #define MU_PAD_KEY mu_pad_key_def() 251 | #define MU_STRIP_KEY mu_strip_key_def() 252 | 253 | #define MU_BIND_KEY mu_bind_key_def() 254 | #define MU_COMP_KEY mu_comp_key_def() 255 | #define MU_MAP_KEY mu_map_key_def() 256 | #define MU_FILTER_KEY mu_filter_key_def() 257 | #define MU_REDUCE_KEY mu_reduce_key_def() 258 | #define MU_ANY_KEY mu_any_key_def() 259 | #define MU_ALL_KEY mu_all_key_def() 260 | 261 | #define MU_ITER_KEY mu_iter_key_def() 262 | #define MU_PAIRS_KEY mu_pairs_key_def() 263 | #define MU_RANGE_KEY mu_range_key_def() 264 | #define MU_REPEAT_KEY mu_repeat_key_def() 265 | #define MU_RANDOM_KEY mu_random_key_def() 266 | 267 | #define MU_ZIP_KEY mu_zip_key_def() 268 | #define MU_CHAIN_KEY mu_chain_key_def() 269 | #define MU_TAKE_KEY mu_take_key_def() 270 | #define MU_DROP_KEY mu_drop_key_def() 271 | 272 | #define MU_MIN_KEY mu_min_key_def() 273 | #define MU_MAX_KEY mu_max_key_def() 274 | #define MU_REVERSE_KEY mu_reverse_key_def() 275 | #define MU_SORT_KEY mu_sort_key_def() 276 | 277 | #define MU_ERROR_KEY mu_error_key_def() 278 | #define MU_PRINT_KEY mu_print_key_def() 279 | #define MU_IMPORT_KEY mu_import_key_def() 280 | 281 | 282 | // Builtin deferating functions 283 | MU_DEF(mu_builtins_def) 284 | 285 | MU_DEF(mu_true_def) 286 | MU_DEF(mu_inf_def) 287 | MU_DEF(mu_ninf_def) 288 | MU_DEF(mu_e_def) 289 | MU_DEF(mu_pi_def) 290 | 291 | MU_DEF(mu_num_def) 292 | MU_DEF(mu_str_def) 293 | MU_DEF(mu_tbl_def) 294 | MU_DEF(mu_fn_def) 295 | 296 | MU_DEF(mu_not_def) 297 | MU_DEF(mu_eq_def) 298 | MU_DEF(mu_neq_def) 299 | MU_DEF(mu_is_def) 300 | MU_DEF(mu_lt_def) 301 | MU_DEF(mu_lte_def) 302 | MU_DEF(mu_gt_def) 303 | MU_DEF(mu_gte_def) 304 | 305 | MU_DEF(mu_add_def) 306 | MU_DEF(mu_sub_def) 307 | MU_DEF(mu_mul_def) 308 | MU_DEF(mu_div_def) 309 | MU_DEF(mu_abs_def) 310 | MU_DEF(mu_floor_def) 311 | MU_DEF(mu_ceil_def) 312 | MU_DEF(mu_idiv_def) 313 | MU_DEF(mu_mod_def) 314 | MU_DEF(mu_pow_def) 315 | MU_DEF(mu_log_def) 316 | 317 | MU_DEF(mu_cos_def) 318 | MU_DEF(mu_acos_def) 319 | MU_DEF(mu_sin_def) 320 | MU_DEF(mu_asin_def) 321 | MU_DEF(mu_tan_def) 322 | MU_DEF(mu_atan_def) 323 | 324 | MU_DEF(mu_and_def) 325 | MU_DEF(mu_or_def) 326 | MU_DEF(mu_xor_def) 327 | MU_DEF(mu_diff_def) 328 | MU_DEF(mu_shl_def) 329 | MU_DEF(mu_shr_def) 330 | 331 | MU_DEF(mu_parse_def) 332 | MU_DEF(mu_repr_def) 333 | MU_DEF(mu_bin_def) 334 | MU_DEF(mu_oct_def) 335 | MU_DEF(mu_hex_def) 336 | 337 | MU_DEF(mu_len_def) 338 | MU_DEF(mu_tail_def) 339 | MU_DEF(mu_push_def) 340 | MU_DEF(mu_pop_def) 341 | MU_DEF(mu_concat_def) 342 | MU_DEF(mu_subset_def) 343 | 344 | MU_DEF(mu_find_def) 345 | MU_DEF(mu_replace_def) 346 | MU_DEF(mu_split_def) 347 | MU_DEF(mu_join_def) 348 | MU_DEF(mu_pad_def) 349 | MU_DEF(mu_strip_def) 350 | 351 | MU_DEF(mu_bind_def) 352 | MU_DEF(mu_comp_def) 353 | MU_DEF(mu_map_def) 354 | MU_DEF(mu_filter_def) 355 | MU_DEF(mu_reduce_def) 356 | MU_DEF(mu_any_def) 357 | MU_DEF(mu_all_def) 358 | 359 | MU_DEF(mu_iter_def) 360 | MU_DEF(mu_pairs_def) 361 | MU_DEF(mu_range_def) 362 | MU_DEF(mu_repeat_def) 363 | MU_DEF(mu_random_def) 364 | 365 | MU_DEF(mu_zip_def) 366 | MU_DEF(mu_chain_def) 367 | MU_DEF(mu_take_def) 368 | MU_DEF(mu_drop_def) 369 | 370 | MU_DEF(mu_min_def) 371 | MU_DEF(mu_max_def) 372 | MU_DEF(mu_reverse_def) 373 | MU_DEF(mu_sort_def) 374 | 375 | MU_DEF(mu_error_def) 376 | MU_DEF(mu_print_def) 377 | MU_DEF(mu_import_def) 378 | 379 | MU_DEF(mu_true_key_def) 380 | MU_DEF(mu_false_key_def) 381 | MU_DEF(mu_inf_key_def) 382 | MU_DEF(mu_ninf_key_def) 383 | MU_DEF(mu_e_key_def) 384 | MU_DEF(mu_pi_key_def) 385 | 386 | MU_DEF(mu_num_key_def) 387 | MU_DEF(mu_str_key_def) 388 | MU_DEF(mu_tbl_key_def) 389 | MU_DEF(mu_fn_key_def) 390 | 391 | MU_DEF(mu_not_key_def) 392 | MU_DEF(mu_eq_key_def) 393 | MU_DEF(mu_neq_key_def) 394 | MU_DEF(mu_is_key_def) 395 | MU_DEF(mu_lt_key_def) 396 | MU_DEF(mu_lte_key_def) 397 | MU_DEF(mu_gt_key_def) 398 | MU_DEF(mu_gte_key_def) 399 | 400 | MU_DEF(mu_add_key_def) 401 | MU_DEF(mu_sub_key_def) 402 | MU_DEF(mu_mul_key_def) 403 | MU_DEF(mu_div_key_def) 404 | MU_DEF(mu_abs_key_def) 405 | MU_DEF(mu_floor_key_def) 406 | MU_DEF(mu_ceil_key_def) 407 | MU_DEF(mu_idiv_key_def) 408 | MU_DEF(mu_mod_key_def) 409 | MU_DEF(mu_pow_key_def) 410 | MU_DEF(mu_log_key_def) 411 | 412 | MU_DEF(mu_cos_key_def) 413 | MU_DEF(mu_acos_key_def) 414 | MU_DEF(mu_sin_key_def) 415 | MU_DEF(mu_asin_key_def) 416 | MU_DEF(mu_tan_key_def) 417 | MU_DEF(mu_atan_key_def) 418 | 419 | MU_DEF(mu_and_key_def) 420 | MU_DEF(mu_or_key_def) 421 | MU_DEF(mu_xor_key_def) 422 | MU_DEF(mu_diff_key_def) 423 | MU_DEF(mu_shl_key_def) 424 | MU_DEF(mu_shr_key_def) 425 | 426 | MU_DEF(mu_parse_key_def) 427 | MU_DEF(mu_repr_key_def) 428 | MU_DEF(mu_ord_key_def) 429 | MU_DEF(mu_chr_key_def) 430 | MU_DEF(mu_bin_key_def) 431 | MU_DEF(mu_oct_key_def) 432 | MU_DEF(mu_hex_key_def) 433 | 434 | MU_DEF(mu_len_key_def) 435 | MU_DEF(mu_tail_key_def) 436 | MU_DEF(mu_push_key_def) 437 | MU_DEF(mu_pop_key_def) 438 | MU_DEF(mu_concat_key_def) 439 | MU_DEF(mu_subset_key_def) 440 | 441 | MU_DEF(mu_find_key_def) 442 | MU_DEF(mu_replace_key_def) 443 | MU_DEF(mu_split_key_def) 444 | MU_DEF(mu_join_key_def) 445 | MU_DEF(mu_pad_key_def) 446 | MU_DEF(mu_strip_key_def) 447 | 448 | MU_DEF(mu_bind_key_def) 449 | MU_DEF(mu_comp_key_def) 450 | MU_DEF(mu_map_key_def) 451 | MU_DEF(mu_filter_key_def) 452 | MU_DEF(mu_reduce_key_def) 453 | MU_DEF(mu_any_key_def) 454 | MU_DEF(mu_all_key_def) 455 | 456 | MU_DEF(mu_iter_key_def) 457 | MU_DEF(mu_pairs_key_def) 458 | MU_DEF(mu_range_key_def) 459 | MU_DEF(mu_repeat_key_def) 460 | MU_DEF(mu_random_key_def) 461 | 462 | MU_DEF(mu_zip_key_def) 463 | MU_DEF(mu_chain_key_def) 464 | MU_DEF(mu_take_key_def) 465 | MU_DEF(mu_drop_key_def) 466 | 467 | MU_DEF(mu_min_key_def) 468 | MU_DEF(mu_max_key_def) 469 | MU_DEF(mu_reverse_key_def) 470 | MU_DEF(mu_sort_key_def) 471 | 472 | MU_DEF(mu_error_key_def) 473 | MU_DEF(mu_print_key_def) 474 | MU_DEF(mu_import_key_def) 475 | 476 | 477 | #endif 478 | -------------------------------------------------------------------------------- /mu/str.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu strs, the representation of strings 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #include "str.h" 8 | #include "mu.h" 9 | 10 | 11 | #define MU_EMPTY_STR mu_empty_str() 12 | #define MU_SPACE_STR mu_space_str() 13 | MU_DEF_STR(mu_empty_str, "") 14 | MU_DEF_STR(mu_space_str, " ") 15 | 16 | 17 | // String access, useful for debugging 18 | mu_inline struct mstr *mstr(mu_t s) { 19 | return (struct mstr *)((muint_t)s & ~7); 20 | } 21 | 22 | 23 | // String interning 24 | // 25 | // Currently interning is implemented using a sorted array with a 26 | // binary search for insertion. This was chosen for a few reasons: 27 | // - We can't reuse the table's implementation since it relies 28 | // on interned strings. 29 | // - Lower memory overhead/more cache friendly than tree 30 | // or trie implementation. 31 | // - Strings don't need to be hashed, its possible strings won't 32 | // even need to be completely scanned during comparisons on 33 | // lookup/insertion. 34 | static mu_t *mu_str_table = 0; 35 | static muint_t mu_str_table_size = 0; 36 | static muint_t mu_str_table_len = 0; 37 | 38 | static mint_t mu_str_table_find(const mbyte_t *s, mlen_t len) { 39 | mint_t min = 0; 40 | mint_t max = mu_str_table_len-1; 41 | 42 | // binary search for existing strings 43 | // strings are sorted first by length to avoid comparisons 44 | while (min <= max) { 45 | mint_t mid = (max + min) / 2; 46 | mint_t cmp = len > mu_str_getlen(mu_str_table[mid]) ? +1 : 47 | len < mu_str_getlen(mu_str_table[mid]) ? -1 : 48 | memcmp(s, mu_str_getdata(mu_str_table[mid]), len); 49 | 50 | if (cmp == 0) { 51 | return mid; 52 | } else if (cmp < 0) { 53 | max = mid-1; 54 | } else { 55 | min = mid+1; 56 | } 57 | } 58 | 59 | // Use inverted values to indicate not found but where to 60 | // insert since 0 is valid in both cases 61 | return ~min; 62 | } 63 | 64 | static void mu_str_table_insert(mint_t i, mu_t s) { 65 | // expand the table if necessary 66 | if (mu_str_table_len == mu_str_table_size) { 67 | muint_t nsize; 68 | mu_t *ntable; 69 | 70 | if (mu_str_table_size == 0) { 71 | nsize = MU_MINALLOC / sizeof(mu_t); 72 | } else { 73 | nsize = mu_str_table_size << 1; 74 | } 75 | 76 | ntable = mu_alloc(nsize * sizeof(mu_t)); 77 | memcpy(ntable, mu_str_table, i * sizeof(mu_t)); 78 | memcpy(&ntable[i+1], &mu_str_table[i], 79 | (mu_str_table_len-i) * sizeof(mu_t)); 80 | mu_dealloc(mu_str_table, mu_str_table_size * sizeof(mu_t)); 81 | 82 | mu_str_table = ntable; 83 | mu_str_table_size = nsize; 84 | } else { 85 | memmove(&mu_str_table[i+1], &mu_str_table[i], 86 | (mu_str_table_len-i) * sizeof(mu_t)); 87 | } 88 | 89 | mu_str_table[i] = s; 90 | mu_str_table_len += 1; 91 | } 92 | 93 | static void mu_str_table_remove(mint_t i) { 94 | mu_str_table_len -= 1; 95 | memmove(&mu_str_table[i], &mu_str_table[i+1], 96 | (mu_str_table_len-i) * sizeof(mu_t)); 97 | } 98 | 99 | 100 | // String management 101 | // This can avoid unnecessary allocations sometimes since 102 | // buf's internal structure is reused for interned strings 103 | mu_t mu_str_intern(mu_t b, muint_t n) { 104 | mu_assert(mu_isbuf(b)); 105 | 106 | mint_t i = mu_str_table_find(mu_buf_getdata(b), n); 107 | if (i >= 0) { 108 | mu_dec(b); 109 | return mu_inc(mu_str_table[i]); 110 | } 111 | 112 | if (mu_buf_getdtor(b)) { 113 | mu_buf_setdtor(&b, 0); 114 | } 115 | 116 | if (mu_buf_getlen(b) != n) { 117 | mu_buf_resize(&b, n); 118 | } 119 | 120 | mu_t s = (mu_t)((muint_t)b - MTBUF + MTSTR); 121 | mu_str_table_insert(~i, s); 122 | return mu_inc(s); 123 | } 124 | 125 | mu_t mu_str_fromdata(const void *s, muint_t n) { 126 | mu_checklen(n <= (mlen_t)-1, "string"); 127 | 128 | mint_t i = mu_str_table_find(s, n); 129 | if (i >= 0) { 130 | return mu_inc(mu_str_table[i]); 131 | } 132 | 133 | // create new string and insert 134 | mu_t b = mu_buf_create(n); 135 | memcpy(mu_buf_getdata(b), s, n); 136 | 137 | mu_t ns = (mu_t)((muint_t)b - MTBUF + MTSTR); 138 | mu_str_table_insert(~i, ns); 139 | return mu_inc(ns); 140 | } 141 | 142 | void mu_str_destroy(mu_t s) { 143 | mint_t i = mu_str_table_find(mu_str_getdata(s), mu_str_getlen(s)); 144 | mu_assert(i >= 0); 145 | mu_str_table_remove(i); 146 | 147 | mu_dealloc((struct mstr *)((muint_t)s - MTSTR), 148 | mu_offsetof(struct mstr, data) + mu_str_getlen(s)); 149 | } 150 | 151 | 152 | // String creating functions 153 | mu_t mu_str_init(const struct mstr *s) { 154 | mu_t m = mu_str_intern((mu_t)((muint_t)s + MTBUF), s->len); 155 | 156 | if (*(mref_t *)((muint_t)m - MTSTR) != 0) { 157 | *(mref_t *)((muint_t)m - MTSTR) = 0; 158 | } 159 | 160 | return m; 161 | } 162 | 163 | mu_t mu_str_frommu(mu_t m) { 164 | switch (mu_gettype(m)) { 165 | case MTNIL: 166 | return MU_EMPTY_STR; 167 | 168 | case MTSTR: 169 | return m; 170 | 171 | default: 172 | return mu_str_format("%r", m); 173 | } 174 | } 175 | 176 | mu_t mu_str_vformat(const char *f, va_list args) { 177 | mu_t b = mu_buf_create(0); 178 | muint_t n = 0; 179 | mu_buf_vpushf(&b, &n, f, args); 180 | return mu_str_intern(b, n); 181 | } 182 | 183 | mu_t mu_str_format(const char *f, ...) { 184 | va_list args; 185 | va_start(args, f); 186 | mu_t m = mu_str_vformat(f, args); 187 | va_end(args); 188 | return m; 189 | } 190 | 191 | 192 | // Comparison operation 193 | mint_t mu_str_cmp(mu_t a, mu_t b) { 194 | mu_assert(mu_isstr(a) && mu_isstr(b)); 195 | 196 | if (a == b) { 197 | return 0; 198 | } 199 | 200 | muint_t alen = mu_str_getlen(a); 201 | muint_t blen = mu_str_getlen(b); 202 | mint_t cmp = memcmp(mu_str_getdata(a), mu_str_getdata(b), 203 | alen < blen ? alen : blen); 204 | 205 | mu_dec(b); 206 | return cmp != 0 ? cmp : alen - blen; 207 | } 208 | 209 | 210 | // String iteration 211 | bool mu_str_next(mu_t s, muint_t *ip, mu_t *cp) { 212 | mu_assert(mu_isstr(s)); 213 | muint_t i = *ip; 214 | 215 | if (i >= mu_str_getlen(s)) { 216 | return false; 217 | } 218 | 219 | if (cp) *cp = mu_str_fromdata((const mbyte_t*)mu_str_getdata(s) + i, 1); 220 | *ip = i + 1; 221 | return true; 222 | } 223 | 224 | static mcnt_t mu_str_step(mu_t scope, mu_t *frame) { 225 | mu_t s = mu_tbl_lookup(scope, mu_num_fromuint(0)); 226 | muint_t i = mu_num_getuint(mu_tbl_lookup(scope, mu_num_fromuint(1))); 227 | 228 | bool next = mu_str_next(s, &i, &frame[0]); 229 | mu_dec(s); 230 | mu_tbl_insert(scope, mu_num_fromuint(1), mu_num_fromuint(i)); 231 | return next ? 1 : 0; 232 | } 233 | 234 | mu_t mu_str_iter(mu_t s) { 235 | mu_assert(mu_isstr(s)); 236 | return mu_fn_fromsbfn(0x00, mu_str_step, 237 | mu_tbl_fromlist((mu_t[]){mu_inc(s), mu_num_fromuint(0)}, 2)); 238 | } 239 | 240 | 241 | // String operations 242 | mu_t mu_str_concat(mu_t a, mu_t b) { 243 | mu_assert(mu_isstr(a) && mu_isstr(b)); 244 | muint_t an = mu_str_getlen(a); 245 | muint_t bn = mu_str_getlen(b); 246 | mu_t d = mu_buf_create(an + bn); 247 | 248 | memcpy((mbyte_t *)mu_buf_getdata(d), mu_str_getdata(a), an); 249 | memcpy((mbyte_t *)mu_buf_getdata(d)+an, mu_str_getdata(b), bn); 250 | 251 | mu_dec(b); 252 | return mu_str_intern(d, an + bn); 253 | } 254 | 255 | mu_t mu_str_subset(mu_t s, mint_t lower, mint_t upper) { 256 | mu_assert(mu_isstr(s)); 257 | lower = (lower >= 0) ? lower : lower + mu_str_getlen(s); 258 | upper = (upper >= 0) ? upper : upper + mu_str_getlen(s); 259 | 260 | if (lower < 0) { 261 | lower = 0; 262 | } 263 | 264 | if (upper > mu_str_getlen(s)) { 265 | upper = mu_str_getlen(s); 266 | } 267 | 268 | if (lower >= upper) { 269 | return MU_EMPTY_STR; 270 | } 271 | 272 | return mu_str_fromdata( 273 | (const mbyte_t *)mu_str_getdata(s) + lower, 274 | upper - lower); 275 | } 276 | 277 | 278 | // String representation 279 | static muint_t mu_str_fromascii(mbyte_t c) { 280 | c |= ('a' ^ 'A'); 281 | return 282 | (c >= '0' && c <= '9') ? c - '0': 283 | (c >= 'a' && c <= 'F') ? c - 'A' + 10 : -1; 284 | } 285 | 286 | mu_t mu_str_parsen(const mbyte_t **ppos, const mbyte_t *end) { 287 | const mbyte_t *pos = *ppos; 288 | mbyte_t quote = *pos++; 289 | mu_t b = mu_buf_create(0); 290 | muint_t n = 0; 291 | 292 | if (quote != '\'' && quote != '"') { 293 | mu_dec(b); 294 | return 0; 295 | } 296 | 297 | while (pos < end-1 && *pos != quote) { 298 | if (*pos == '\\') { 299 | if (pos[1] == 'b' && pos < end-9 && 300 | (mu_str_fromascii(pos[2]) < 2 && 301 | mu_str_fromascii(pos[3]) < 2 && 302 | mu_str_fromascii(pos[4]) < 2 && 303 | mu_str_fromascii(pos[5]) < 2 && 304 | mu_str_fromascii(pos[6]) < 2 && 305 | mu_str_fromascii(pos[7]) < 2 && 306 | mu_str_fromascii(pos[8]) < 2 && 307 | mu_str_fromascii(pos[9]) < 2)) { 308 | mu_buf_pushc(&b, &n, 309 | mu_str_fromascii(pos[2])*2*2*2*2*2*2*2 + 310 | mu_str_fromascii(pos[3])*2*2*2*2*2*2 + 311 | mu_str_fromascii(pos[4])*2*2*2*2*2 + 312 | mu_str_fromascii(pos[5])*2*2*2*2 + 313 | mu_str_fromascii(pos[6])*2*2*2 + 314 | mu_str_fromascii(pos[7])*2*2 + 315 | mu_str_fromascii(pos[8])*2 + 316 | mu_str_fromascii(pos[9])); 317 | pos += 10; 318 | } else if (pos[1] == 'o' && pos < end-4 && 319 | (mu_str_fromascii(pos[2]) < 8 && 320 | mu_str_fromascii(pos[3]) < 8 && 321 | mu_str_fromascii(pos[4]) < 8)) { 322 | mu_buf_pushc(&b, &n, 323 | mu_str_fromascii(pos[2])*8*8 + 324 | mu_str_fromascii(pos[3])*8 + 325 | mu_str_fromascii(pos[4])); 326 | pos += 5; 327 | } else if (pos[1] == 'd' && pos < end-4 && 328 | (mu_str_fromascii(pos[2]) < 10 && 329 | mu_str_fromascii(pos[3]) < 10 && 330 | mu_str_fromascii(pos[4]) < 10)) { 331 | mu_buf_pushc(&b, &n, 332 | mu_str_fromascii(pos[2])*10*10 + 333 | mu_str_fromascii(pos[3])*10 + 334 | mu_str_fromascii(pos[4])); 335 | pos += 5; 336 | } else if (pos[1] == 'x' && pos < end-3 && 337 | (mu_str_fromascii(pos[2]) < 16 && 338 | mu_str_fromascii(pos[3]) < 16)) { 339 | mu_buf_pushc(&b, &n, 340 | mu_str_fromascii(pos[2])*16 + 341 | mu_str_fromascii(pos[3])); 342 | pos += 4; 343 | } else if (pos[1] == '\\') { 344 | mu_buf_pushc(&b, &n, '\\'); pos += 2; 345 | } else if (pos[1] == '\'') { 346 | mu_buf_pushc(&b, &n, '\''); pos += 2; 347 | } else if (pos[1] == '\"') { 348 | mu_buf_pushc(&b, &n, '\"'); pos += 2; 349 | } else if (pos[1] == 'f') { 350 | mu_buf_pushc(&b, &n, '\f'); pos += 2; 351 | } else if (pos[1] == 'n') { 352 | mu_buf_pushc(&b, &n, '\n'); pos += 2; 353 | } else if (pos[1] == 'r') { 354 | mu_buf_pushc(&b, &n, '\r'); pos += 2; 355 | } else if (pos[1] == 't') { 356 | mu_buf_pushc(&b, &n, '\t'); pos += 2; 357 | } else if (pos[1] == 'v') { 358 | mu_buf_pushc(&b, &n, '\v'); pos += 2; 359 | } else if (pos[1] == '0') { 360 | mu_buf_pushc(&b, &n, '\0'); pos += 2; 361 | } else { 362 | mu_buf_pushc(&b, &n, '\\'); pos += 1; 363 | } 364 | } else { 365 | mu_buf_pushc(&b, &n, *pos++); 366 | } 367 | } 368 | 369 | if (quote != *pos++) { 370 | mu_dec(b); 371 | return 0; 372 | } 373 | 374 | *ppos = pos; 375 | return mu_str_intern(b, n); 376 | } 377 | 378 | mu_t mu_str_parse(const char *s, muint_t n) { 379 | const mbyte_t *pos = (const mbyte_t *)s; 380 | const mbyte_t *end = (const mbyte_t *)pos + n; 381 | 382 | mu_t m = mu_str_parsen(&pos, end); 383 | 384 | if (pos != end) { 385 | mu_dec(m); 386 | return 0; 387 | } 388 | 389 | return m; 390 | } 391 | 392 | // Returns a string representation of a string 393 | mu_t mu_str_repr(mu_t m) { 394 | mu_assert(mu_isstr(m)); 395 | const mbyte_t *pos = mu_str_getdata(m); 396 | const mbyte_t *end = pos + mu_str_getlen(m); 397 | mu_t b = mu_buf_create(2 + mu_str_getlen(m)); 398 | muint_t n = 0; 399 | 400 | mu_buf_pushc(&b, &n, '\''); 401 | 402 | for (; pos < end; pos++) { 403 | if (*pos < ' ' || *pos > '~' || 404 | *pos == '\\' || *pos == '\'') { 405 | if (*pos == '\\') mu_buf_pushf(&b, &n, "\\\\"); 406 | else if (*pos == '\'') mu_buf_pushf(&b, &n, "\\'"); 407 | else if (*pos == '\f') mu_buf_pushf(&b, &n, "\\f"); 408 | else if (*pos == '\n') mu_buf_pushf(&b, &n, "\\n"); 409 | else if (*pos == '\r') mu_buf_pushf(&b, &n, "\\r"); 410 | else if (*pos == '\t') mu_buf_pushf(&b, &n, "\\t"); 411 | else if (*pos == '\v') mu_buf_pushf(&b, &n, "\\v"); 412 | else if (*pos == '\0') mu_buf_pushf(&b, &n, "\\0"); 413 | else mu_buf_pushf(&b, &n, "\\x%bx", *pos); 414 | } else { 415 | mu_buf_pushc(&b, &n, *pos); 416 | } 417 | } 418 | 419 | mu_buf_pushc(&b, &n, '\''); 420 | return mu_str_intern(b, n); 421 | } 422 | 423 | 424 | // String related functions in Mu 425 | static mcnt_t mu_str_bfn(mu_t *frame) { 426 | mu_t m = mu_str_frommu(mu_inc(frame[0])); 427 | mu_checkargs(m, MU_STR_KEY, 0x1, frame); 428 | mu_dec(frame[0]); 429 | frame[0] = m; 430 | return 1; 431 | } 432 | 433 | MU_DEF_STR(mu_str_key_def, "str") 434 | MU_DEF_BFN(mu_str_def, 0x1, mu_str_bfn) 435 | 436 | static mcnt_t mu_find_bfn(mu_t *frame) { 437 | mu_t s = frame[0]; 438 | mu_t m = frame[1]; 439 | mu_checkargs(mu_isstr(s) && mu_isstr(m), 440 | MU_FIND_KEY, 0x2, frame); 441 | 442 | const mbyte_t *sb = mu_str_getdata(s); 443 | mlen_t slen = mu_str_getlen(s); 444 | const mbyte_t *mb = mu_str_getdata(m); 445 | mlen_t mlen = mu_str_getlen(m); 446 | 447 | for (muint_t i = 0; i+mlen <= slen; i++) { 448 | if (memcmp(&sb[i], mb, mlen) == 0) { 449 | mu_dec(m); 450 | mu_dec(s); 451 | frame[0] = mu_num_fromuint(i); 452 | frame[1] = mu_num_fromuint(i + mlen); 453 | return 2; 454 | } 455 | } 456 | 457 | mu_dec(s); 458 | mu_dec(m); 459 | return 0; 460 | } 461 | 462 | MU_DEF_STR(mu_find_key_def, "find") 463 | MU_DEF_BFN(mu_find_def, 0x2, mu_find_bfn) 464 | 465 | static mcnt_t mu_replace_bfn(mu_t *frame) { 466 | mu_t s = frame[0]; 467 | mu_t m = frame[1]; 468 | mu_t r = frame[2]; 469 | mu_checkargs(mu_isstr(s) && mu_isstr(m) && mu_isstr(r), 470 | MU_REPLACE, 0x3, frame); 471 | 472 | const mbyte_t *sb = mu_str_getdata(s); 473 | mlen_t slen = mu_str_getlen(s); 474 | const mbyte_t *mb = mu_str_getdata(m); 475 | mlen_t mlen = mu_str_getlen(m); 476 | 477 | mu_t d = mu_buf_create(slen); 478 | muint_t n = 0; 479 | muint_t i = 0; 480 | 481 | while (i+mlen <= slen) { 482 | bool match = memcmp(&sb[i], mb, mlen) == 0; 483 | 484 | if (match) { 485 | mu_buf_pushmu(&d, &n, mu_inc(r)); 486 | i += mlen; 487 | } 488 | 489 | if (!match || mlen == 0) { 490 | mu_buf_pushc(&d, &n, sb[i]); 491 | i += 1; 492 | } 493 | } 494 | 495 | mu_buf_pushdata(&d, &n, &sb[i], slen-i); 496 | 497 | mu_dec(s); 498 | mu_dec(m); 499 | mu_dec(r); 500 | frame[0] = mu_str_intern(d, n); 501 | return 1; 502 | } 503 | 504 | MU_DEF_STR(mu_replace_key_def, "replace") 505 | MU_DEF_BFN(mu_replace_def, 0x3, mu_replace_bfn) 506 | 507 | 508 | static mcnt_t mu_str_split_step(mu_t scope, mu_t *frame) { 509 | mu_t a = mu_tbl_lookup(scope, mu_num_fromuint(0)); 510 | const mbyte_t *ab = mu_str_getdata(a); 511 | mlen_t alen = mu_str_getlen(a); 512 | muint_t i = mu_num_getuint(mu_tbl_lookup(scope, mu_num_fromuint(2))); 513 | 514 | if (i > alen) { 515 | mu_dec(a); 516 | return 0; 517 | } 518 | 519 | mu_t s = mu_tbl_lookup(scope, mu_num_fromuint(1)); 520 | const mbyte_t *sb = mu_str_getdata(s); 521 | mlen_t slen = mu_str_getlen(s); 522 | 523 | muint_t j = i; 524 | for (; j < alen; j++) { 525 | if (j+slen <= alen && memcmp(&ab[j], sb, slen) == 0) { 526 | break; 527 | } 528 | } 529 | 530 | frame[0] = mu_str_fromdata(ab+i, j-i); 531 | mu_tbl_insert(scope, mu_num_fromuint(2), mu_num_fromuint(j+slen)); 532 | mu_dec(a); 533 | mu_dec(s); 534 | return 1; 535 | } 536 | 537 | static mcnt_t mu_split_bfn(mu_t *frame) { 538 | mu_t s = frame[0]; 539 | mu_t delim = frame[1] ? frame[1] : MU_EMPTY_STR; 540 | mu_checkargs(mu_isstr(s) && mu_isstr(delim), MU_SPLIT_KEY, 0x2, frame); 541 | 542 | if (mu_str_getlen(delim) == 0) { 543 | frame[0] = mu_str_iter(s); 544 | mu_dec(s); 545 | return 1; 546 | } 547 | 548 | frame[0] = mu_fn_fromsbfn(0x0, mu_str_split_step, 549 | mu_tbl_fromlist((mu_t[]){s, delim, mu_num_fromuint(0)}, 3)); 550 | return 1; 551 | } 552 | 553 | MU_DEF_STR(mu_split_key_def, "split") 554 | MU_DEF_BFN(mu_split_def, 0x2, mu_split_bfn) 555 | 556 | static mcnt_t mu_join_bfn(mu_t *frame) { 557 | mu_t iter = frame[0]; 558 | mu_t delim = frame[1] ? frame[1] : MU_EMPTY_STR; 559 | mu_checkargs(mu_isstr(delim), MU_JOIN_KEY, 0x2, frame); 560 | 561 | mu_t b = mu_buf_create(0); 562 | muint_t n = 0; 563 | bool first = true; 564 | 565 | iter = mu_fn_call(MU_ITER, 0x11, iter); 566 | 567 | while (mu_fn_next(iter, 0x1, frame)) { 568 | if (!mu_isstr(frame[0])) { 569 | mu_errorf("invalid value %r passed to join", frame[0]); 570 | } 571 | 572 | if (first) { 573 | first = false; 574 | } else { 575 | mu_buf_pushmu(&b, &n, mu_inc(delim)); 576 | } 577 | 578 | mu_buf_pushmu(&b, &n, frame[0]); 579 | } 580 | 581 | mu_dec(iter); 582 | mu_dec(delim); 583 | frame[0] = mu_str_intern(b, n); 584 | return 1; 585 | } 586 | 587 | MU_DEF_STR(mu_join_key_def, "join") 588 | MU_DEF_BFN(mu_join_def, 0x2, mu_join_bfn) 589 | 590 | static mcnt_t mu_pad_bfn(mu_t *frame) { 591 | mu_t s = frame[0]; 592 | mu_t mlen = frame[1]; 593 | mu_t pad = frame[2] ? frame[2] : MU_SPACE_STR; 594 | mu_checkargs( 595 | mu_isstr(s) && mu_isnum(mlen) && 596 | mu_isstr(pad) && mu_str_getlen(pad) > 0, 597 | MU_PAD_KEY, 0x3, frame); 598 | 599 | bool left; 600 | muint_t len; 601 | 602 | if (mu_num_cmp(mlen, mu_num_fromuint(0)) < 0) { 603 | left = false; 604 | len = mu_num_getuint(mu_num_neg(mlen)); 605 | } else { 606 | left = true; 607 | len = mu_num_getuint(mlen); 608 | } 609 | 610 | if (mu_str_getlen(s) >= len) { 611 | mu_dec(pad); 612 | return 1; 613 | } 614 | 615 | mu_t d = mu_buf_create(len); 616 | muint_t n = 0; 617 | muint_t count = (len - mu_str_getlen(s)) / mu_str_getlen(pad); 618 | 619 | if (left) { 620 | mu_buf_pushmu(&d, &n, s); 621 | } 622 | 623 | for (muint_t i = 0; i < count; i++) { 624 | mu_buf_pushmu(&d, &n, mu_inc(pad)); 625 | } 626 | 627 | if (!left) { 628 | mu_buf_pushmu(&d, &n, s); 629 | } 630 | 631 | mu_dec(pad); 632 | frame[0] = mu_str_intern(d, n); 633 | return 1; 634 | } 635 | 636 | MU_DEF_STR(mu_pad_key_def, "pad") 637 | MU_DEF_BFN(mu_pad_def, 0x3, mu_pad_bfn) 638 | 639 | static mcnt_t mu_strip_bfn(mu_t *frame) { 640 | if (mu_isstr(frame[1])) { 641 | mu_dec(frame[2]); 642 | frame[2] = frame[1]; 643 | frame[1] = 0; 644 | } 645 | 646 | mu_t s = frame[0]; 647 | mu_t dir = frame[1]; 648 | mu_t pad = frame[2] ? frame[2] : MU_SPACE_STR; 649 | mu_checkargs( 650 | mu_isstr(s) && (!dir || mu_isnum(dir)) && 651 | mu_isstr(pad) && mu_str_getlen(pad) > 0, 652 | MU_STR_KEY, 0x3, frame); 653 | 654 | const mbyte_t *pos = mu_str_getdata(s); 655 | const mbyte_t *end = pos + mu_str_getlen(s); 656 | 657 | const mbyte_t *pb = mu_str_getdata(pad); 658 | mlen_t plen = mu_str_getlen(pad); 659 | 660 | if (!dir || mu_num_cmp(dir, mu_num_fromuint(0)) <= 0) { 661 | while (end-pos >= plen && memcmp(pos, pb, plen) == 0) { 662 | pos += plen; 663 | } 664 | } 665 | 666 | if (!dir || mu_num_cmp(dir, mu_num_fromuint(0)) >= 0) { 667 | while (end-pos >= plen && memcmp(end-plen, pb, plen) == 0) { 668 | end -= plen; 669 | } 670 | } 671 | 672 | frame[0] = mu_str_fromdata(pos, end-pos); 673 | mu_dec(s); 674 | mu_dec(pad); 675 | return 1; 676 | } 677 | 678 | MU_DEF_STR(mu_strip_key_def, "strip") 679 | MU_DEF_BFN(mu_strip_def, 0x3, mu_strip_bfn) 680 | -------------------------------------------------------------------------------- /mu/num.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu num, the representation of numbers 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #include "num.h" 8 | #include "mu.h" 9 | 10 | #include 11 | 12 | 13 | // Binary digits of precision 14 | #ifdef MU64 15 | #define MU_DIGITS (52 - 3) 16 | #else 17 | #define MU_DIGITS (23 - 3) 18 | #endif 19 | 20 | 21 | // Number constants 22 | MU_DEF_STR(mu_inf_key_def, "inf") 23 | MU_DEF_STR(mu_e_key_def, "E") 24 | MU_DEF_STR(mu_pi_key_def, "PI") 25 | 26 | MU_DEF_FLOAT(mu_inf_def, INFINITY) 27 | MU_DEF_FLOAT(mu_ninf_def, -INFINITY) 28 | MU_DEF_FLOAT(mu_e_def, 2.71828182845904523536) 29 | MU_DEF_FLOAT(mu_pi_def, 3.14159265358979323846) 30 | 31 | 32 | // Number creating macro assuming NaN and -0 not possible 33 | mu_inline mu_t mnum(mfloat_t n) { 34 | return (mu_t)(MTNUM + (~7 & 35 | ((union { mfloat_t n; muint_t u; }){(mfloat_t)n}).u)); 36 | } 37 | 38 | // Conversion from floats 39 | // Number cannot be NaNs or negative zero to garuntee bitwise equality 40 | mu_t mu_num_fromfloat(mfloat_t n) { 41 | if (n != n) { 42 | mu_errorf("operation resulted in nan"); 43 | } 44 | 45 | if (n == 0) { 46 | n = 0; 47 | } 48 | 49 | return mnum(n); 50 | } 51 | 52 | mu_t mu_num_frommu(mu_t m) { 53 | switch (mu_gettype(m)) { 54 | case MTNIL: 55 | return mu_num_fromuint(0); 56 | 57 | case MTNUM: 58 | return m; 59 | 60 | case MTSTR: { 61 | mu_t n = mu_num_parse( 62 | mu_str_getdata(m), 63 | mu_str_getlen(m)); 64 | mu_dec(m); 65 | return n; 66 | } 67 | 68 | default: 69 | mu_dec(m); 70 | return 0; 71 | } 72 | } 73 | 74 | muint_t mu_num_clampuint(mu_t n, muint_t lower, muint_t upper) { 75 | if (mu_num_cmp(n, mu_num_fromuint(lower)) < 0) { 76 | return lower; 77 | } else if (mu_num_cmp(n, mu_num_fromuint(upper)) > 0) { 78 | return upper; 79 | } else { 80 | return mu_num_getuint(n); 81 | } 82 | } 83 | 84 | mint_t mu_num_clampint(mu_t n, mint_t lower, mint_t upper) { 85 | if (mu_num_cmp(n, mu_num_fromint(lower)) < 0) { 86 | return lower; 87 | } else if (mu_num_cmp(n, mu_num_fromint(upper)) > 0) { 88 | return upper; 89 | } else { 90 | return mu_num_getint(n); 91 | } 92 | } 93 | 94 | // Comparison operation 95 | mint_t mu_num_cmp(mu_t a, mu_t b) { 96 | mu_assert(mu_isnum(a) && mu_isnum(b)); 97 | mfloat_t afloat = mu_num_getfloat(a); 98 | mfloat_t bfloat = mu_num_getfloat(b); 99 | 100 | return afloat > bfloat ? +1 : 101 | afloat < bfloat ? -1 : 0; 102 | } 103 | 104 | 105 | // Arithmetic operations 106 | mu_t mu_num_neg(mu_t a) { 107 | mu_assert(mu_isnum(a)); 108 | 109 | if (a == mu_num_fromuint(0)) { 110 | return a; 111 | } else { 112 | return mnum(-mu_num_getfloat(a)); 113 | } 114 | } 115 | 116 | mu_t mu_num_add(mu_t a, mu_t b) { 117 | mu_assert(mu_isnum(a) && mu_isnum(b)); 118 | return mu_num_fromfloat(mu_num_getfloat(a) + mu_num_getfloat(b)); 119 | } 120 | 121 | mu_t mu_num_sub(mu_t a, mu_t b) { 122 | mu_assert(mu_isnum(a) && mu_isnum(b)); 123 | return mu_num_fromfloat(mu_num_getfloat(a) - mu_num_getfloat(b)); 124 | } 125 | 126 | mu_t mu_num_mul(mu_t a, mu_t b) { 127 | mu_assert(mu_isnum(a) && mu_isnum(b)); 128 | return mu_num_fromfloat(mu_num_getfloat(a) * mu_num_getfloat(b)); 129 | } 130 | 131 | mu_t mu_num_div(mu_t a, mu_t b) { 132 | mu_assert(mu_isnum(a) && mu_isnum(b)); 133 | return mu_num_fromfloat(mu_num_getfloat(a) / mu_num_getfloat(b)); 134 | } 135 | 136 | mu_t mu_num_idiv(mu_t a, mu_t b) { 137 | mu_assert(mu_isnum(a) && mu_isnum(b)); 138 | return mu_num_fromfloat(floor(mu_num_getfloat(a) / mu_num_getfloat(b))); 139 | } 140 | 141 | mu_t mu_num_mod(mu_t a, mu_t b) { 142 | mu_assert(mu_isnum(a) && mu_isnum(b)); 143 | mfloat_t base = mu_num_getfloat(b); 144 | mfloat_t mod = fmod(mu_num_getfloat(a), base); 145 | 146 | // Handle truncation for negative values 147 | if (mod*base < 0) { 148 | mod += base; 149 | } 150 | 151 | return mu_num_fromfloat(mod); 152 | } 153 | 154 | mu_t mu_num_pow(mu_t a, mu_t b) { 155 | mu_assert(mu_isnum(a) && mu_isnum(b)); 156 | return mu_num_fromfloat(pow(mu_num_getfloat(a), mu_num_getfloat(b))); 157 | } 158 | 159 | mu_t mu_num_log(mu_t a, mu_t b) { 160 | mu_assert(mu_isnum(a) && (!b || mu_isnum(b))); 161 | return mu_num_fromfloat( 162 | log(mu_num_getfloat(a)) / log(mu_num_getfloat(b ? b : MU_E))); 163 | } 164 | 165 | mu_t mu_num_abs(mu_t a) { 166 | mu_assert(mu_isnum(a)); 167 | return mnum(fabs(mu_num_getfloat(a))); 168 | } 169 | 170 | mu_t mu_num_floor(mu_t a) { 171 | mu_assert(mu_isnum(a)); 172 | return mu_num_fromfloat(floor(mu_num_getfloat(a))); 173 | } 174 | 175 | mu_t mu_num_ceil(mu_t a) { 176 | mu_assert(mu_isnum(a)); 177 | return mu_num_fromfloat(ceil(mu_num_getfloat(a))); 178 | } 179 | 180 | mu_t mu_num_cos(mu_t a) { 181 | mu_assert(mu_isnum(a)); 182 | return mu_num_fromfloat(cos(mu_num_getfloat(a))); 183 | } 184 | 185 | mu_t mu_num_acos(mu_t a) { 186 | mu_assert(mu_isnum(a)); 187 | return mu_num_fromfloat(acos(mu_num_getfloat(a))); 188 | } 189 | 190 | mu_t mu_num_sin(mu_t a) { 191 | mu_assert(mu_isnum(a)); 192 | return mu_num_fromfloat(sin(mu_num_getfloat(a))); 193 | } 194 | 195 | mu_t mu_num_asin(mu_t a) { 196 | mu_assert(mu_isnum(a)); 197 | return mu_num_fromfloat(asin(mu_num_getfloat(a))); 198 | } 199 | 200 | mu_t mu_num_tan(mu_t a) { 201 | mu_assert(mu_isnum(a)); 202 | return mu_num_fromfloat(tan(mu_num_getfloat(a))); 203 | } 204 | 205 | mu_t mu_num_atan(mu_t a, mu_t b) { 206 | mu_assert(mu_isnum(a) && (!b || mu_isnum(b))); 207 | 208 | if (!b) { 209 | return mu_num_fromfloat(atan(mu_num_getfloat(a))); 210 | } else { 211 | return mu_num_fromfloat(atan2(mu_num_getfloat(a), mu_num_getfloat(b))); 212 | } 213 | } 214 | 215 | // Bitwise operations 216 | mu_t mu_num_not(mu_t a) { 217 | mu_assert(mu_isnum(a)); 218 | return mu_num_fromuint((muinth_t)(~mu_num_getuint(a))); 219 | } 220 | 221 | mu_t mu_num_and(mu_t a, mu_t b) { 222 | mu_assert(mu_isnum(a) && mu_isnum(b)); 223 | return mu_num_fromuint((muinth_t)(mu_num_getuint(a) & mu_num_getuint(b))); 224 | } 225 | 226 | mu_t mu_num_or(mu_t a, mu_t b) { 227 | mu_assert(mu_isnum(a) && mu_isnum(b)); 228 | return mu_num_fromuint((muinth_t)(mu_num_getuint(a) | mu_num_getuint(b))); 229 | } 230 | 231 | mu_t mu_num_xor(mu_t a, mu_t b) { 232 | mu_assert(mu_isnum(a) && mu_isnum(b)); 233 | return mu_num_fromuint((muinth_t)(mu_num_getuint(a) ^ mu_num_getuint(b))); 234 | } 235 | 236 | 237 | mu_t mu_num_shl(mu_t a, mu_t b) { 238 | mu_assert(mu_isnum(a) && mu_isnum(b)); 239 | return mu_num_fromuint((muint_t)(mu_num_getuint(a) << mu_num_getuint(b))); 240 | } 241 | 242 | mu_t mu_num_shr(mu_t a, mu_t b) { 243 | mu_assert(mu_isnum(a) && mu_isnum(b)); 244 | return mu_num_fromuint((muint_t)(mu_num_getuint(a) >> mu_num_getuint(b))); 245 | } 246 | 247 | 248 | // Convert string representation to variable 249 | static muint_t mu_num_fromascii(mbyte_t c) { 250 | c |= ('a' ^ 'A'); 251 | return 252 | (c >= '0' && c <= '9') ? c - '0': 253 | (c >= 'a' && c <= 'f') ? c - 'a' + 10 : -1; 254 | } 255 | 256 | static mbyte_t mu_num_toascii(muint_t c) { 257 | return (c < 10) ? '0' + c : 'a' + (c-10); 258 | } 259 | 260 | mu_t mu_num_parsen(const mbyte_t **ppos, const mbyte_t *end) { 261 | const mbyte_t *pos = *ppos; 262 | mu_t n = mu_num_fromuint(0); 263 | mu_t sign = mu_num_fromint(+1); 264 | muint_t base = 10; 265 | 266 | if (pos == end) { 267 | return 0; 268 | } 269 | 270 | if (pos < end && *pos == '+') { 271 | sign = mu_num_fromint(+1); pos++; 272 | } else if (pos < end && *pos == '-') { 273 | sign = mu_num_fromint(-1); pos++; 274 | } 275 | 276 | if (pos+2 < end && memcmp(pos, "inf", 3) == 0) { 277 | *ppos = pos + 3; 278 | return mu_num_mul(sign, MU_INF); 279 | } 280 | 281 | if (pos+2 < end && pos[0] == '0') { 282 | if (pos[1] == 'b' || pos[1] == 'B') { 283 | base = 2; pos += 2; 284 | } else if (pos[1] == 'o' || pos[1] == 'O') { 285 | base = 8; pos += 2; 286 | } else if (pos[1] == 'd' || pos[1] == 'D') { 287 | base = 10; pos += 2; 288 | } else if (pos[1] == 'x' || pos[1] == 'X') { 289 | base = 16; pos += 2; 290 | } 291 | } 292 | 293 | while (pos < end && mu_num_fromascii(*pos) < base) { 294 | n = mu_num_mul(n, mu_num_fromuint(base)); 295 | n = mu_num_add(n, mu_num_fromuint(mu_num_fromascii(*pos++))); 296 | } 297 | 298 | if (pos < end && *pos == '.') { 299 | mu_t scale = mu_num_fromuint(1); 300 | pos++; 301 | 302 | while (pos < end && mu_num_fromascii(*pos) < base) { 303 | scale = mu_num_mul(scale, mu_num_fromuint(base)); 304 | n = mu_num_add(n, mu_num_div( 305 | mu_num_fromuint(mu_num_fromascii(*pos++)), scale)); 306 | } 307 | } 308 | 309 | if (pos < end && (*pos == 'e' || *pos == 'E' || 310 | *pos == 'p' || *pos == 'p')) { 311 | mu_t expbase = mu_num_fromuint((*pos == 'e' || *pos == 'E') ? 10 : 2); 312 | mu_t exp = mu_num_fromuint(0); 313 | mu_t sign = mu_num_fromint(+1); 314 | pos++; 315 | 316 | if (pos < end && *pos == '+') { 317 | sign = mu_num_fromint(+1); pos++; 318 | } else if (pos < end && *pos == '-') { 319 | sign = mu_num_fromint(-1); pos++; 320 | } 321 | 322 | while (pos < end && mu_num_fromascii(*pos) < 10) { 323 | exp = mu_num_mul(exp, mu_num_fromuint(10)); 324 | exp = mu_num_add(exp, mu_num_fromuint(mu_num_fromascii(*pos++))); 325 | } 326 | 327 | n = mu_num_mul(n, mu_num_pow(expbase, mu_num_mul(sign, exp))); 328 | } 329 | 330 | *ppos = pos; 331 | return mu_num_mul(sign, n); 332 | } 333 | 334 | mu_t mu_num_parse(const char *s, muint_t n) { 335 | const mbyte_t *pos = (const mbyte_t *)s; 336 | const mbyte_t *end = (const mbyte_t *)pos + n; 337 | 338 | mu_t m = mu_num_parsen(&pos, end); 339 | 340 | if (pos != end) { 341 | return 0; 342 | } 343 | 344 | return m; 345 | } 346 | 347 | // Obtains a string representation of a number 348 | static void mu_num_base_ipart(mu_t *s, muint_t *i, mu_t n, mu_t base) { 349 | muint_t j = *i; 350 | 351 | while (mu_num_cmp(n, mu_num_fromuint(0)) > 0) { 352 | mu_t d = mu_num_mod(n, base); 353 | mu_buf_pushc(s, i, mu_num_toascii(mu_num_getuint(d))); 354 | n = mu_num_idiv(n, base); 355 | } 356 | 357 | mbyte_t *a = (mbyte_t *)mu_buf_getdata(*s) + j; 358 | mbyte_t *b = (mbyte_t *)mu_buf_getdata(*s) + *i - 1; 359 | 360 | while (a < b) { 361 | mbyte_t t = *a; 362 | *a = *b; 363 | *b = t; 364 | a++; b--; 365 | } 366 | } 367 | 368 | static void mu_num_base_fpart(mu_t *s, muint_t *i, mu_t n, 369 | mu_t base, muint_t digits) { 370 | mu_t error = mu_num_pow(base, mu_num_fromint(-digits)); 371 | mu_t digit = mu_num_fromint(-1); 372 | n = mu_num_mod(n, mu_num_fromuint(1)); 373 | 374 | for (muint_t j = 0; j < digits; j++) { 375 | if (mu_num_cmp(n, error) <= 0) { 376 | break; 377 | } 378 | 379 | if (digit == mu_num_fromint(-1)) { 380 | mu_buf_pushc(s, i, '.'); 381 | } 382 | 383 | mu_t p = mu_num_pow(base, digit); 384 | mu_t d = mu_num_idiv(n, p); 385 | mu_buf_pushc(s, i, mu_num_toascii(mu_num_getuint(d))); 386 | 387 | n = mu_num_mod(n, p); 388 | digit = mu_num_sub(digit, mu_num_fromuint(1)); 389 | } 390 | } 391 | 392 | static mu_t mu_num_base(mu_t n, char c, mu_t base, char expc, mu_t expbase) { 393 | if (n == mu_num_fromuint(0)) { 394 | if (c) return mu_str_format("0%c0", c); 395 | else return mu_str_format("0"); 396 | } else if (n == MU_INF) { 397 | return mu_str_format("+inf"); 398 | } else if (n == MU_NINF) { 399 | return mu_str_format("-inf"); 400 | } else { 401 | mu_t s = mu_buf_create(0); 402 | muint_t i = 0; 403 | 404 | if (mu_num_cmp(n, mu_num_fromuint(0)) < 0) { 405 | n = mu_num_neg(n); 406 | mu_buf_pushc(&s, &i, '-'); 407 | } 408 | 409 | if (c) { 410 | mu_buf_pushdata(&s, &i, (mbyte_t[2]){'0', c}, 2); 411 | } 412 | 413 | mu_t exp = mu_num_floor(mu_num_log(n, expbase)); 414 | mu_t sig = mu_num_floor(mu_num_log(n, base)); 415 | mu_t digits = mu_num_ceil(mu_num_div(mu_num_fromuint(MU_DIGITS), 416 | mu_num_log(base, mu_num_fromuint(2)))); 417 | 418 | bool scientific = mu_num_cmp(sig, digits) >= 0 || 419 | mu_num_cmp(sig, mu_num_fromint(-1)) < 0; 420 | 421 | if (scientific) { 422 | n = mu_num_div(n, mu_num_pow(expbase, exp)); 423 | } 424 | 425 | muint_t j = i; 426 | mu_num_base_ipart(&s, &i, n, base); 427 | mu_num_base_fpart(&s, &i, n, base, mu_num_getuint(digits) - (i-j)); 428 | 429 | if (scientific) { 430 | mu_buf_pushc(&s, &i, expc); 431 | 432 | if (mu_num_cmp(exp, mu_num_fromuint(0)) < 0) { 433 | exp = mu_num_neg(exp); 434 | mu_buf_pushc(&s, &i, '-'); 435 | } 436 | 437 | mu_num_base_ipart(&s, &i, exp, mu_num_fromuint(10)); 438 | } 439 | 440 | return mu_str_intern(s, i); 441 | } 442 | } 443 | 444 | mu_t mu_num_repr(mu_t n) { 445 | mu_assert(mu_isnum(n)); 446 | return mu_num_base(n, 0, mu_num_fromuint(10), 'e', mu_num_fromuint(10)); 447 | } 448 | 449 | mu_t mu_num_bin(mu_t n) { 450 | mu_assert(mu_isnum(n)); 451 | return mu_num_base(n, 'b', mu_num_fromuint(2), 'p', mu_num_fromuint(2)); 452 | } 453 | 454 | mu_t mu_num_oct(mu_t n) { 455 | mu_assert(mu_isnum(n)); 456 | return mu_num_base(n, 'o', mu_num_fromuint(8), 'p', mu_num_fromuint(2)); 457 | } 458 | 459 | mu_t mu_num_hex(mu_t n) { 460 | mu_assert(mu_isnum(n)); 461 | return mu_num_base(n, 'x', mu_num_fromuint(16), 'p', mu_num_fromuint(2)); 462 | } 463 | 464 | 465 | // Number related Mu functions 466 | static mcnt_t mu_num_bfn(mu_t *frame) { 467 | mu_t m = mu_num_frommu(mu_inc(frame[0])); 468 | mu_checkargs(m, MU_NUM_KEY, 0x1, frame); 469 | mu_dec(frame[0]); 470 | frame[0] = m; 471 | 472 | return 1; 473 | } 474 | 475 | MU_DEF_STR(mu_num_key_def, "num") 476 | MU_DEF_BFN(mu_num_def, 0x1, mu_num_bfn) 477 | 478 | static mcnt_t mu_add_bfn(mu_t *frame) { 479 | mu_t a = frame[0]; 480 | mu_t b = frame[1]; 481 | mu_checkargs(mu_isnum(a) && (!b || mu_isnum(b)), 482 | MU_ADD_KEY, 0x2, frame); 483 | 484 | if (!b) { 485 | frame[0] = a; 486 | } else { 487 | frame[0] = mu_num_add(a, b); 488 | } 489 | 490 | return 1; 491 | } 492 | 493 | MU_DEF_STR(mu_add_key_def, "+") 494 | MU_DEF_BFN(mu_add_def, 0x2, mu_add_bfn) 495 | 496 | static mcnt_t mu_sub_bfn(mu_t *frame) { 497 | mu_t a = frame[0]; 498 | mu_t b = frame[1]; 499 | mu_checkargs(mu_isnum(a) && (!b || mu_isnum(b)), 500 | MU_SUB_KEY, 0x2, frame); 501 | 502 | if (!b) { 503 | frame[0] = mu_num_neg(a); 504 | } else { 505 | frame[0] = mu_num_sub(a, b); 506 | } 507 | 508 | return 1; 509 | } 510 | 511 | MU_DEF_STR(mu_sub_key_def, "-") 512 | MU_DEF_BFN(mu_sub_def, 0x2, mu_sub_bfn) 513 | 514 | static mcnt_t mu_mul_bfn(mu_t *frame) { 515 | mu_t a = frame[0]; 516 | mu_t b = frame[1]; 517 | mu_checkargs(mu_isnum(a) && mu_isnum(b), 518 | MU_SUB_KEY, 0x2, frame); 519 | 520 | frame[0] = mu_num_mul(a, b); 521 | return 1; 522 | } 523 | 524 | MU_DEF_STR(mu_mul_key_def, "*") 525 | MU_DEF_BFN(mu_mul_def, 0x2, mu_mul_bfn) 526 | 527 | static mcnt_t mu_div_bfn(mu_t *frame) { 528 | mu_t a = frame[0]; 529 | mu_t b = frame[1]; 530 | mu_checkargs(mu_isnum(a) && mu_isnum(b), 531 | MU_MUL_KEY, 0x2, frame); 532 | 533 | frame[0] = mu_num_div(a, b); 534 | return 1; 535 | } 536 | 537 | MU_DEF_STR(mu_div_key_def, "/") 538 | MU_DEF_BFN(mu_div_def, 0x2, mu_div_bfn) 539 | 540 | static mcnt_t mu_abs_bfn(mu_t *frame) { 541 | mu_t a = frame[0]; 542 | mu_checkargs(mu_isnum(a), MU_ABS_KEY, 0x1, frame); 543 | 544 | frame[0] = mu_num_abs(a); 545 | return 1; 546 | } 547 | 548 | MU_DEF_STR(mu_abs_key_def, "abs") 549 | MU_DEF_BFN(mu_abs_def, 0x1, mu_abs_bfn) 550 | 551 | static mcnt_t mu_floor_bfn(mu_t *frame) { 552 | mu_t a = frame[0]; 553 | mu_checkargs(mu_isnum(a), MU_FLOOR_KEY, 0x1, frame); 554 | 555 | frame[0] = mu_num_floor(a); 556 | return 1; 557 | } 558 | 559 | MU_DEF_STR(mu_floor_key_def, "floor") 560 | MU_DEF_BFN(mu_floor_def, 0x1, mu_floor_bfn) 561 | 562 | static mcnt_t mu_ceil_bfn(mu_t *frame) { 563 | mu_t a = frame[0]; 564 | mu_checkargs(mu_isnum(a), MU_CEIL_KEY, 0x1, frame); 565 | 566 | frame[0] = mu_num_ceil(a); 567 | return 1; 568 | } 569 | 570 | MU_DEF_STR(mu_ceil_key_def, "ceil") 571 | MU_DEF_BFN(mu_ceil_def, 0x1, mu_ceil_bfn) 572 | 573 | static mcnt_t mu_idiv_bfn(mu_t *frame) { 574 | mu_t a = frame[0]; 575 | mu_t b = frame[1]; 576 | mu_checkargs(mu_isnum(a) && mu_isnum(b), 577 | MU_IDIV_KEY, 0x2, frame); 578 | 579 | frame[0] = mu_num_idiv(a, b); 580 | return 1; 581 | } 582 | 583 | MU_DEF_STR(mu_idiv_key_def, "//") 584 | MU_DEF_BFN(mu_idiv_def, 0x2, mu_idiv_bfn) 585 | 586 | static mcnt_t mu_mod_bfn(mu_t *frame) { 587 | mu_t a = frame[0]; 588 | mu_t b = frame[1]; 589 | mu_checkargs(mu_isnum(a) && mu_isnum(b), 590 | MU_IDIV_KEY, 0x2, frame); 591 | 592 | frame[0] = mu_num_mod(a, b); 593 | return 1; 594 | } 595 | 596 | MU_DEF_STR(mu_mod_key_def, "%") 597 | MU_DEF_BFN(mu_mod_def, 0x2, mu_mod_bfn) 598 | 599 | static mcnt_t mu_pow_bfn(mu_t *frame) { 600 | mu_t a = frame[0]; 601 | mu_t b = frame[1]; 602 | mu_checkargs(mu_isnum(a) && mu_isnum(b), 603 | MU_POW_KEY, 0x2, frame); 604 | 605 | frame[0] = mu_num_pow(a, b); 606 | return 1; 607 | } 608 | 609 | MU_DEF_STR(mu_pow_key_def, "^") 610 | MU_DEF_BFN(mu_pow_def, 0x2, mu_pow_bfn) 611 | 612 | static mcnt_t mu_log_bfn(mu_t *frame) { 613 | mu_t a = frame[0]; 614 | mu_t b = frame[1]; 615 | mu_checkargs(mu_isnum(a) && (!b || mu_isnum(b)), 616 | MU_LOG_KEY, 0x2, frame); 617 | 618 | frame[0] = mu_num_log(a, b); 619 | return 1; 620 | } 621 | 622 | MU_DEF_STR(mu_log_key_def, "log") 623 | MU_DEF_BFN(mu_log_def, 0x2, mu_log_bfn) 624 | 625 | static mcnt_t mu_cos_bfn(mu_t *frame) { 626 | mu_t a = frame[0]; 627 | mu_checkargs(mu_isnum(a), MU_COS_KEY, 0x1, frame); 628 | 629 | frame[0] = mu_num_cos(a); 630 | return 1; 631 | } 632 | 633 | MU_DEF_STR(mu_cos_key_def, "cos") 634 | MU_DEF_BFN(mu_cos_def, 0x1, mu_cos_bfn) 635 | 636 | static mcnt_t mu_acos_bfn(mu_t *frame) { 637 | mu_t a = frame[0]; 638 | mu_checkargs(mu_isnum(a), MU_COS_KEY, 0x1, frame); 639 | 640 | frame[0] = mu_num_acos(a); 641 | return 1; 642 | } 643 | 644 | MU_DEF_STR(mu_acos_key_def, "acos") 645 | MU_DEF_BFN(mu_acos_def, 0x1, mu_acos_bfn) 646 | 647 | static mcnt_t mu_sin_bfn(mu_t *frame) { 648 | mu_t a = frame[0]; 649 | mu_checkargs(mu_isnum(a), MU_SIN_KEY, 0x1, frame); 650 | 651 | frame[0] = mu_num_sin(a); 652 | return 1; 653 | } 654 | 655 | MU_DEF_STR(mu_sin_key_def, "sin") 656 | MU_DEF_BFN(mu_sin_def, 0x1, mu_sin_bfn) 657 | 658 | static mcnt_t mu_asin_bfn(mu_t *frame) { 659 | mu_t a = frame[0]; 660 | mu_checkargs(mu_isnum(a), MU_ASIN_KEY, 0x1, frame); 661 | 662 | frame[0] = mu_num_asin(a); 663 | return 1; 664 | } 665 | 666 | MU_DEF_STR(mu_asin_key_def, "asin") 667 | MU_DEF_BFN(mu_asin_def, 0x1, mu_asin_bfn) 668 | 669 | static mcnt_t mu_tan_bfn(mu_t *frame) { 670 | mu_t a = frame[0]; 671 | mu_checkargs(mu_isnum(a), MU_TAN_KEY, 0x1, frame); 672 | 673 | frame[0] = mu_num_tan(a); 674 | return 1; 675 | } 676 | 677 | MU_DEF_STR(mu_tan_key_def, "tan") 678 | MU_DEF_BFN(mu_tan_def, 0x1, mu_tan_bfn) 679 | 680 | static mcnt_t mu_atan_bfn(mu_t *frame) { 681 | mu_t a = frame[0]; 682 | mu_t b = frame[1]; 683 | mu_checkargs(mu_isnum(a) && (!b || mu_isnum(b)), 684 | MU_ATAN_KEY, 0x2, frame); 685 | 686 | frame[0] = mu_num_atan(a, b); 687 | return 1; 688 | } 689 | 690 | MU_DEF_STR(mu_atan_key_def, "atan") 691 | MU_DEF_BFN(mu_atan_def, 0x2, mu_atan_bfn) 692 | 693 | static mcnt_t mu_shl_bfn(mu_t *frame) { 694 | mu_t a = frame[0]; 695 | mu_t b = frame[1]; 696 | mu_checkargs(mu_isnum(a) && mu_isnum(b), 697 | MU_SHL_KEY, 0x2, frame); 698 | 699 | frame[0] = mu_num_shl(a, b); 700 | return 1; 701 | } 702 | 703 | MU_DEF_STR(mu_shl_key_def, "<<") 704 | MU_DEF_BFN(mu_shl_def, 0x2, mu_shl_bfn) 705 | 706 | static mcnt_t mu_shr_bfn(mu_t *frame) { 707 | mu_t a = frame[0]; 708 | mu_t b = frame[1]; 709 | mu_checkargs(mu_isnum(a) && mu_isnum(b), 710 | MU_SHR_KEY, 0x2, frame); 711 | 712 | frame[0] = mu_num_shr(a, b); 713 | return 1; 714 | } 715 | 716 | MU_DEF_STR(mu_shr_key_def, ">>") 717 | MU_DEF_BFN(mu_shr_def, 0x2, mu_shr_bfn) 718 | 719 | 720 | // Random number deferation 721 | // Based on xorshift128+ with wordsize as seed/output 722 | #ifdef MU64 723 | #define XORSHIFT1 23 724 | #define XORSHIFT2 17 725 | #define XORSHIFT3 26 726 | #else 727 | #define XORSHIFT1 15 728 | #define XORSHIFT2 18 729 | #define XORSHIFT3 11 730 | #endif 731 | 732 | static mcnt_t mu_num_randomstep(mu_t scope, mu_t *frame) { 733 | muint_t *a = mu_buf_getdata(scope); 734 | muint_t x = a[0]; 735 | muint_t y = a[1]; 736 | 737 | x ^= x << XORSHIFT1; 738 | x ^= x >> XORSHIFT2; 739 | x ^= y ^ (y >> XORSHIFT3); 740 | 741 | a[0] = y; 742 | a[1] = x; 743 | frame[0] = mu_num_div(mu_num_fromuint(x + y), 744 | mu_num_add(mu_num_fromuint((muint_t)-1), mu_num_fromuint(1))); 745 | return 1; 746 | } 747 | 748 | static mcnt_t mu_num_random(mu_t *frame) { 749 | mu_t seed = frame[0] ? frame[0] : mu_num_fromuint(0); 750 | mu_checkargs(mu_isnum(seed), MU_RANDOM_KEY, 0x1, frame); 751 | 752 | frame[0] = mu_fn_fromsbfn(0x0, mu_num_randomstep, mu_buf_fromdata( 753 | (mu_t[]){seed, seed}, 2*sizeof(mu_t))); 754 | return 1; 755 | } 756 | 757 | MU_DEF_STR(mu_random_key_def, "random") 758 | MU_DEF_BFN(mu_random_def, 0x1, mu_num_random) 759 | -------------------------------------------------------------------------------- /mu/tbl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Mu tbls, key-value lookup tables 3 | * 4 | * Copyright (c) 2016 Christopher Haster 5 | * Distributed under the MIT license in mu.h 6 | */ 7 | #include "tbl.h" 8 | #include "mu.h" 9 | 10 | 11 | // Table access 12 | mu_inline struct mtbl *mtbl(mu_t t) { 13 | return (struct mtbl *)((muint_t)t & ~7); 14 | } 15 | 16 | mu_inline bool mu_isrtbl(mu_t t) { 17 | return (MTTBL^MTRTBL) & (muint_t)t; 18 | } 19 | 20 | 21 | // General purpose hash for mu types 22 | mu_inline muint_t mu_tbl_hash(mu_t t, mu_t m) { 23 | // Mu types have bitwise equality but aren't distributed very well. 24 | // 25 | // We can kinda fix this with Knuth's multiplicitive hash 26 | // (2^32 / golden ratio), but multiplication only propogates entropy 27 | // upwards, and later masking will lose most of the integer's variation. 28 | // So instead of masking, we just shift the integer downwards, keeping the 29 | // most impacted bits. 30 | #ifdef MU64 31 | return ((muint_t)m * 11400714819323198485UL) >> (64 - mtbl(t)->npw2); 32 | #else 33 | return ((muint_t)m * 2654435761UL) >> (32 - mtbl(t)->npw2); 34 | #endif 35 | } 36 | 37 | // Find smallest integer size for table length 38 | static muintq_t mu_tbl_isize(mlen_t len) { 39 | if (len > 3221225472) { 40 | return 8; 41 | } else if (len > 57344) { 42 | return 4; 43 | } else if (len > 240) { 44 | return 2; 45 | } else { 46 | return 1; 47 | } 48 | } 49 | 50 | // Find next power of 2 needed for list or table 51 | static muintq_t mu_tbl_listnpw2(mlen_t len) { 52 | if (len < MU_MINALLOC/sizeof(mu_t)) { 53 | len = MU_MINALLOC/sizeof(mu_t); 54 | } 55 | 56 | return mu_npw2(len); 57 | } 58 | 59 | static muintq_t mu_tbl_pairsnpw2(mlen_t len, muintq_t *pisize) { 60 | const muintq_t psize = 2*sizeof(mu_t); 61 | 62 | // Calculate space for indices, order is important for correct rounding 63 | muintq_t isize = mu_tbl_isize(len); 64 | muint_t indices = ((muint_t)psize*len + psize-1) / (psize - isize); 65 | if (indices < MU_MINALLOC/psize) { 66 | indices = MU_MINALLOC/psize; 67 | } 68 | 69 | *pisize = isize; 70 | return mu_npw2(indices); 71 | } 72 | 73 | // Other calculated attributes of tables 74 | mu_inline bool mu_tbl_islist(mu_t t) { 75 | return mtbl(t)->isize == 0; 76 | } 77 | 78 | mu_inline muint_t mu_tbl_count(mu_t t) { 79 | return mtbl(t)->len + mtbl(t)->nils; 80 | } 81 | 82 | mu_inline muint_t mu_tbl_size(mu_t t) { 83 | return (1 << mtbl(t)->npw2); 84 | } 85 | 86 | mu_inline muint_t mu_tbl_off(mu_t t) { 87 | // This looks complicated but most of these are constants and powers of 2 88 | const muintq_t psize = 2*sizeof(mu_t); 89 | return (mtbl(t)->isize*mu_tbl_size(t) + psize-1) / psize; 90 | } 91 | 92 | // Indirect entry access 93 | static mu_t *mu_tbl_getpair(mu_t t, muint_t i) { 94 | muint_t off = 0; 95 | if (mtbl(t)->isize == 1) { 96 | off = ((uint8_t*)mtbl(t)->array)[i]; 97 | } else if (mtbl(t)->isize == 2) { 98 | off = ((uint16_t*)mtbl(t)->array)[i]; 99 | } else if (mtbl(t)->isize == 4) { 100 | off = ((uint32_t*)mtbl(t)->array)[i]; 101 | } else if (mtbl(t)->isize == 8) { 102 | off = ((uint64_t*)mtbl(t)->array)[i]; 103 | } 104 | 105 | return off ? &mtbl(t)->array[2*off] : 0; 106 | } 107 | 108 | static void mu_tbl_setpair(mu_t t, muint_t i, mu_t *p) { 109 | muint_t j = (p - mtbl(t)->array)/2; 110 | if (mtbl(t)->isize == 1) { 111 | ((uint8_t*)mtbl(t)->array)[i] = j; 112 | } else if (mtbl(t)->isize == 2) { 113 | ((uint16_t*)mtbl(t)->array)[i] = j; 114 | } else if (mtbl(t)->isize == 4) { 115 | ((uint32_t*)mtbl(t)->array)[i] = j; 116 | } else if (mtbl(t)->isize == 8) { 117 | ((uint64_t*)mtbl(t)->array)[i] = j; 118 | } 119 | } 120 | 121 | 122 | // Functions for managing tables 123 | mu_t mu_tbl_create(muint_t len) { 124 | struct mtbl *t = mu_alloc(sizeof(struct mtbl)); 125 | t->ref = 1; 126 | t->npw2 = mu_tbl_listnpw2(len); 127 | t->isize = 0; 128 | t->len = 0; 129 | t->nils = 0; 130 | t->tail = 0; 131 | 132 | muint_t size = 1 << t->npw2; 133 | t->array = mu_alloc(size * sizeof(mu_t)); 134 | memset(t->array, 0, size * sizeof(mu_t)); 135 | 136 | return (mu_t)((muint_t)t + MTTBL); 137 | } 138 | 139 | mu_t mu_tbl_createtail(muint_t len, mu_t tail) { 140 | mu_t t = mu_tbl_create(len); 141 | mu_tbl_settail(t, tail); 142 | return t; 143 | } 144 | 145 | void mu_tbl_settail(mu_t t, mu_t tail) { 146 | mu_assert(!tail || mu_istbl(tail) || mu_isbuf(tail)); 147 | mu_checkconst(!mu_isrtbl(t), "table"); 148 | 149 | if (mu_isbuf(tail)) { 150 | mu_t b = tail; 151 | tail = mu_buf_gettail(b); 152 | mu_dec(b); 153 | } 154 | 155 | mtbl(t)->tail = tail; 156 | } 157 | 158 | void mu_tbl_destroy(mu_t t) { 159 | muint_t i = (mu_tbl_islist(t) ? 1 : 2) * mu_tbl_off(t); 160 | muint_t len = (mu_tbl_islist(t) ? 1 : 2) * mu_tbl_count(t); 161 | muint_t size = (mu_tbl_islist(t) ? 1 : 2) * mu_tbl_size(t); 162 | for (; i < len; i++) { 163 | mu_dec(mtbl(t)->array[i]); 164 | } 165 | 166 | mu_dealloc(mtbl(t)->array, size*sizeof(mu_t)); 167 | mu_dec(mtbl(t)->tail); 168 | mu_dealloc(mtbl(t), sizeof(struct mtbl)); 169 | } 170 | 171 | 172 | // Recursively looks up a key in the table 173 | // returns either that value or nil 174 | mu_t mu_tbl_lookup(mu_t t, mu_t k) { 175 | mu_assert(mu_istbl(t)); 176 | if (!k) { 177 | return 0; 178 | } 179 | 180 | for (; t; t = mtbl(t)->tail) { 181 | muint_t mask = (1 << mtbl(t)->npw2) - 1; 182 | 183 | if (mu_tbl_islist(t)) { 184 | muint_t i = mu_num_getuint(k) & mask; 185 | 186 | if (k == mu_num_fromuint(i)) { 187 | return mu_inc(mtbl(t)->array[i]); 188 | } 189 | } else { 190 | for (muint_t i = mu_tbl_hash(t, k);; i++) { 191 | mu_t *p = mu_tbl_getpair(t, i & mask); 192 | 193 | if (p && p[0] == k) { 194 | mu_dec(k); 195 | return mu_inc(p[1]); 196 | } else if (!p) { 197 | break; 198 | } 199 | } 200 | } 201 | } 202 | 203 | mu_dec(k); 204 | return 0; 205 | } 206 | 207 | 208 | // Expands into list/table, possibly converting from a list 209 | static void mu_tbl_listexpand(mu_t t, mlen_t len) { 210 | mu_t *oldarray = mtbl(t)->array; 211 | muint_t oldcount = mu_tbl_count(t); 212 | muint_t oldsize = mu_tbl_size(t); 213 | 214 | mtbl(t)->npw2 = mu_tbl_listnpw2(len); 215 | mtbl(t)->array = mu_alloc(mu_tbl_size(t)*sizeof(mu_t)); 216 | memset(mtbl(t)->array, 0, mu_tbl_size(t)*sizeof(mu_t)); 217 | 218 | memcpy(mtbl(t)->array, oldarray, oldcount*sizeof(mu_t)); 219 | mu_dealloc(oldarray, oldsize*sizeof(mu_t)); 220 | } 221 | 222 | static void mu_tbl_pairsexpand(mu_t t, mlen_t len) { 223 | bool waslist = mu_tbl_islist(t); 224 | mu_t *oldarray = mtbl(t)->array; 225 | muint_t oldoff = mu_tbl_off(t); 226 | muint_t oldcount = mu_tbl_count(t); 227 | muint_t oldsize = mu_tbl_size(t); 228 | 229 | mtbl(t)->npw2 = mu_tbl_pairsnpw2(len, &mtbl(t)->isize); 230 | mtbl(t)->len = 0; 231 | mtbl(t)->nils = 0; 232 | mtbl(t)->array = mu_alloc(2*mu_tbl_size(t)*sizeof(mu_t)); 233 | memset(mtbl(t)->array, 0, 2*mu_tbl_off(t)*sizeof(mu_t)); 234 | 235 | for (muint_t i = 0; i < oldcount; i++) { 236 | if (waslist) { 237 | mu_tbl_insert(t, mu_num_fromuint(i), oldarray[i]); 238 | } else { 239 | mu_tbl_insert(t, oldarray[2*(i+oldoff)+0], 240 | oldarray[2*(i+oldoff)+1]); 241 | } 242 | } 243 | 244 | mu_dealloc(oldarray, (waslist ? 1 : 2)*oldsize*sizeof(mu_t)); 245 | } 246 | 247 | // Inserts a value in the table with the given key 248 | // without decending down the tail chain 249 | void mu_tbl_insert(mu_t t, mu_t k, mu_t v) { 250 | mu_assert(mu_istbl(t)); 251 | mu_checkconst(!mu_isrtbl(t), "table"); 252 | if (!k) { 253 | mu_dec(v); 254 | return; 255 | } 256 | 257 | muint_t mask = (1 << mtbl(t)->npw2) - 1; 258 | 259 | if (mu_tbl_islist(t)) { 260 | muint_t i = mu_num_getuint(k) & mask; 261 | 262 | if (k == mu_num_fromuint(i) && mtbl(t)->array[i]) { 263 | // replace old value 264 | mu_t oldv = mtbl(t)->array[i]; 265 | mtbl(t)->array[i] = v; 266 | mtbl(t)->len += (v ? 1 : 0) - 1; 267 | mtbl(t)->nils += (!v ? 1 : 0); 268 | mu_dec(oldv); 269 | return; 270 | } else if (!v) { 271 | // nothing to remove 272 | return; 273 | } else { 274 | mu_checklen((muint_t)mtbl(t)->len + 1 <= (mlen_t)-1, "table"); 275 | 276 | if (k != mu_num_fromuint(i)) { 277 | muint_t i = mu_num_getuint(k) & (2*mask+1); 278 | if (k == mu_num_fromuint(i)) { 279 | // just needs bigger list 280 | mu_tbl_listexpand(t, i+1); 281 | mu_tbl_insert(t, k, v); 282 | return; 283 | } else { 284 | // needs table 285 | mu_tbl_pairsexpand(t, mtbl(t)->len+1); 286 | mu_tbl_insert(t, k, v); 287 | return; 288 | } 289 | } 290 | 291 | // new value fits 292 | mtbl(t)->array[i] = v; 293 | mtbl(t)->len += 1; 294 | mtbl(t)->nils += i - (mtbl(t)->len-1); 295 | return; 296 | } 297 | } else { 298 | for (muint_t i = mu_tbl_hash(t, k);; i++) { 299 | mu_t *p = mu_tbl_getpair(t, i & mask); 300 | 301 | if (p && p[0] == k) { 302 | // replace old value 303 | mu_t oldv = p[1]; 304 | p[1] = v; 305 | mtbl(t)->len += (v ? 1 : 0) - (oldv ? 1 : 0); 306 | mtbl(t)->nils += (!v ? 1 : 0) - (!oldv ? 1 : 0); 307 | mu_dec(k); 308 | mu_dec(oldv); 309 | return; 310 | } else if (!p && !v) { 311 | // nothing to remove 312 | return; 313 | } else if (!p) { 314 | mu_checklen((muint_t)mtbl(t)->len + 1 <= (mlen_t)-1, "table"); 315 | 316 | muint_t j = mu_tbl_off(t) + mu_tbl_count(t); 317 | if (j >= mu_tbl_size(t)) { 318 | // needs bigger table 319 | mu_tbl_pairsexpand(t, mtbl(t)->len+1); 320 | mu_tbl_insert(t, k, v); 321 | return; 322 | } 323 | 324 | mtbl(t)->array[2*j+0] = k; 325 | mtbl(t)->array[2*j+1] = v; 326 | mtbl(t)->len += 1; 327 | mu_tbl_setpair(t, i & mask, &mtbl(t)->array[2*j]); 328 | return; 329 | } 330 | } 331 | } 332 | } 333 | 334 | // Recursively assigns a value in the table with the given key 335 | // decends down the tail chain until its found 336 | void mu_tbl_assign(mu_t head, mu_t k, mu_t v) { 337 | mu_assert(mu_istbl(head)); 338 | bool ro = false; 339 | if (!k) { 340 | mu_dec(k); 341 | return; 342 | } 343 | 344 | for (mu_t t = head; t; t = mtbl(t)->tail) { 345 | ro = ro || mu_isrtbl(t); 346 | muint_t mask = (1 << mtbl(t)->npw2) - 1; 347 | 348 | if (mu_tbl_islist(t)) { 349 | muint_t i = mu_num_getuint(k) & mask; 350 | 351 | if (k == mu_num_fromuint(i) && mtbl(t)->array[i]) { 352 | mu_checkconst(!ro, "table"); 353 | 354 | // replace old value 355 | mu_t oldv = mtbl(t)->array[i]; 356 | mtbl(t)->array[i] = v; 357 | mtbl(t)->len += (v ? 1 : 0) - 1; 358 | mtbl(t)->nils += (!v ? 1 : 0); 359 | mu_dec(oldv); 360 | return; 361 | } 362 | } else { 363 | for (muint_t i = mu_tbl_hash(t, k);; i++) { 364 | mu_t *p = mu_tbl_getpair(t, i & mask); 365 | 366 | if (p && p[0] == k && p[1]) { 367 | mu_checkconst(!ro, "table"); 368 | 369 | // replace old value 370 | mu_t oldv = p[1]; 371 | p[1] = v; 372 | mtbl(t)->len += (v ? 1 : 0) - (oldv ? 1 : 0); 373 | mtbl(t)->nils -= (v ? 1 : 0) - (oldv ? 1 : 0); 374 | mu_dec(k); 375 | mu_dec(oldv); 376 | return; 377 | } else if (!p) { 378 | break; 379 | } 380 | } 381 | } 382 | } 383 | 384 | if (!v) { 385 | mu_dec(k); 386 | return; 387 | } 388 | 389 | mu_tbl_insert(head, k, v); 390 | } 391 | 392 | 393 | // Performs iteration on a table 394 | bool mu_tbl_next(mu_t t, muint_t *ip, mu_t *kp, mu_t *vp) { 395 | mu_assert(mu_istbl(t)); 396 | muint_t off = mu_tbl_off(t); 397 | muint_t count = mu_tbl_count(t); 398 | muint_t i = *ip; 399 | mu_t k, v; 400 | 401 | do { 402 | if (i >= count) { 403 | return false; 404 | } 405 | 406 | if (mu_tbl_islist(t)) { 407 | k = mu_num_fromuint(i); 408 | v = mtbl(t)->array[i]; 409 | } else { 410 | k = mtbl(t)->array[2*(i+off)+0]; 411 | v = mtbl(t)->array[2*(i+off)+1]; 412 | } 413 | 414 | i++; 415 | } while (!v); 416 | 417 | if (kp) *kp = mu_inc(k); 418 | if (vp) *vp = mu_inc(v); 419 | *ip = i; 420 | return true; 421 | } 422 | 423 | static mcnt_t mu_tbl_iter_step(mu_t scope, mu_t *frame) { 424 | mu_t t = mu_tbl_lookup(scope, mu_num_fromuint(0)); 425 | muint_t i = mu_num_getuint(mu_tbl_lookup(scope, mu_num_fromuint(1))); 426 | 427 | bool next = mu_tbl_next(t, &i, 0, &frame[0]); 428 | mu_dec(t); 429 | mu_tbl_insert(scope, mu_num_fromuint(1), mu_num_fromuint(i)); 430 | return next ? 1 : 0; 431 | } 432 | 433 | mu_t mu_tbl_iter(mu_t t) { 434 | mu_assert(mu_istbl(t)); 435 | return mu_fn_fromsbfn(0x0, mu_tbl_iter_step, 436 | mu_tbl_fromlist((mu_t[]){mu_inc(t), mu_num_fromuint(0)}, 2)); 437 | } 438 | 439 | static mcnt_t mu_tbl_pairs_step(mu_t scope, mu_t *frame) { 440 | mu_t t = mu_tbl_lookup(scope, mu_num_fromuint(0)); 441 | muint_t i = mu_num_getuint(mu_tbl_lookup(scope, mu_num_fromuint(1))); 442 | 443 | bool next = mu_tbl_next(t, &i, &frame[0], &frame[1]); 444 | mu_dec(t); 445 | mu_tbl_insert(scope, mu_num_fromuint(1), mu_num_fromuint(i)); 446 | return next ? 2 : 0; 447 | } 448 | 449 | mu_t mu_tbl_pairs(mu_t t) { 450 | mu_assert(mu_istbl(t)); 451 | return mu_fn_fromsbfn(0x0, mu_tbl_pairs_step, 452 | mu_tbl_fromlist((mu_t[]){mu_inc(t), mu_num_fromuint(0)}, 2)); 453 | } 454 | 455 | 456 | // Table creating functions 457 | mu_t mu_tbl_initlist(struct mtbl *t, mu_t (*const *def)(void), muint_t n) { 458 | mu_t m = (mu_t)((muint_t)t + MTTBL); 459 | 460 | for (muint_t i = 0; i < n; i++) { 461 | if (def[i]) { 462 | mu_tbl_insert(m, mu_num_fromuint(i), def[i]()); 463 | } 464 | } 465 | 466 | return (mu_t)((muint_t)t + MTRTBL); 467 | } 468 | 469 | mu_t mu_tbl_initpairs(struct mtbl *t, mu_t (*tail)(void), 470 | mu_t (*const (*def)[2])(void), muint_t n) { 471 | mu_t m = (mu_t)((muint_t)t + MTTBL); 472 | if (tail) { 473 | mu_tbl_settail(m, tail()); 474 | } 475 | 476 | for (muint_t i = 0; i < n; i++) { 477 | if (def[i][0] && def[i][1]) { 478 | mu_tbl_insert(m, def[i][0](), def[i][1]()); 479 | } 480 | } 481 | 482 | return (mu_t)((muint_t)t + MTRTBL); 483 | } 484 | 485 | mu_t mu_tbl_fromlist(mu_t *list, muint_t n) { 486 | mu_t t = mu_tbl_create(n); 487 | 488 | for (muint_t i = 0; i < n; i++) { 489 | mu_tbl_insert(t, mu_num_fromuint(i), list[i]); 490 | } 491 | 492 | return t; 493 | } 494 | 495 | mu_t mu_tbl_frompairs(mu_t (*pairs)[2], muint_t n) { 496 | mu_t t = mu_tbl_create(n); 497 | 498 | for (muint_t i = 0; i < n; i++) { 499 | mu_tbl_insert(t, pairs[i][0], pairs[i][1]); 500 | } 501 | 502 | return t; 503 | } 504 | 505 | static mu_t mu_tbl_fromiter(mu_t i) { 506 | mu_t frame[MU_FRAME]; 507 | mu_t t = mu_tbl_create(0); 508 | muint_t index = 0; 509 | 510 | while (mu_fn_next(i, 0x2, frame)) { 511 | if (frame[1]) { 512 | mu_tbl_insert(t, frame[0], frame[1]); 513 | } else { 514 | mu_tbl_insert(t, mu_num_fromuint(index++), frame[0]); 515 | } 516 | } 517 | 518 | mu_dec(i); 519 | return t; 520 | } 521 | 522 | mu_t mu_tbl_frommu(mu_t m) { 523 | switch (mu_gettype(m)) { 524 | case MTNIL: 525 | return mu_tbl_create(0); 526 | 527 | case MTNUM: 528 | return mu_tbl_create(mu_num_getuint(m)); 529 | 530 | case MTSTR: 531 | return mu_tbl_fromiter(mu_fn_call(MU_ITER, 0x11, m)); 532 | 533 | case MTTBL: 534 | case MTRTBL: 535 | return mu_tbl_fromiter(mu_fn_call(MU_PAIRS, 0x11, m)); 536 | 537 | case MTFN: 538 | return mu_tbl_fromiter(m); 539 | 540 | default: 541 | mu_dec(m); 542 | return 0; 543 | } 544 | } 545 | 546 | // Table operations 547 | void mu_tbl_push(mu_t t, mu_t p, mint_t i) { 548 | mu_assert(mu_istbl(t)); 549 | mu_checkconst(!mu_isrtbl(t), "table"); 550 | i = (i >= 0) ? i : i + mtbl(t)->len; 551 | i = (i > mtbl(t)->len) ? mtbl(t)->len : (i < 0) ? 0 : i; 552 | 553 | if (mu_tbl_count(t) + 1 >= mu_tbl_size(t)) { 554 | mu_checklen((muint_t)mtbl(t)->len + 1 <= (mlen_t)-1, "table"); 555 | 556 | if (mu_tbl_islist(t)) { 557 | mu_tbl_listexpand(t, mu_tbl_count(t)+1); 558 | } else { 559 | mu_tbl_pairsexpand(t, mu_tbl_count(t)+1); 560 | } 561 | } 562 | 563 | if (mu_tbl_islist(t)) { 564 | memmove(&mtbl(t)->array[i+1], &mtbl(t)->array[i], 565 | (mu_tbl_size(t)-(i+1))*sizeof(mu_t)); 566 | mtbl(t)->array[i] = p; 567 | mtbl(t)->len += (p ? 1 : 0); 568 | } else { 569 | muint_t off = mu_tbl_off(t); 570 | muint_t count = mu_tbl_count(t); 571 | mtbl(t)->len = 0; 572 | mtbl(t)->nils = 0; 573 | memset(mtbl(t)->array, 0, mu_tbl_size(t)); 574 | 575 | for (muint_t j = 0; j < i; j++) { 576 | if (!mtbl(t)->array[2*(j+off)+1]) { 577 | i++; 578 | } else { 579 | mu_tbl_insert(t, mtbl(t)->array[2*(j+off)+0], 580 | mtbl(t)->array[2*(j+off)+1]); 581 | } 582 | } 583 | 584 | memmove(&mtbl(t)->array[2*(i+1+off)], &mtbl(t)->array[2*(i+off)], 585 | 2*(mu_tbl_size(t)-(i+1+off))*sizeof(mu_t)); 586 | mu_tbl_insert(t, mu_num_fromuint(i), p); 587 | 588 | for (muint_t j = i; j < count; j++) { 589 | mu_t k = mtbl(t)->array[2*(j+1+off)+0]; 590 | if (mu_isnum(k)) { 591 | k = mu_num_add(k, mu_num_fromuint(1)); 592 | } 593 | 594 | mu_tbl_insert(t, k, mtbl(t)->array[2*(j+1+off)+1]); 595 | } 596 | } 597 | } 598 | 599 | mu_t mu_tbl_pop(mu_t t, mint_t i) { 600 | mu_assert(mu_istbl(t)); 601 | mu_checkconst(!mu_isrtbl(t), "table"); 602 | i = (i >= 0) ? i : i + mtbl(t)->len; 603 | i = (i > mtbl(t)->len) ? mtbl(t)->len : (i < 0) ? 0 : i; 604 | 605 | if (mu_tbl_islist(t)) { 606 | mu_t p = mtbl(t)->array[i]; 607 | memmove(&mtbl(t)->array[i], &mtbl(t)->array[i+1], 608 | (mu_tbl_size(t)-(i+1))*sizeof(mu_t)); 609 | mtbl(t)->len -= (p ? 1 : 0); 610 | return p; 611 | } else { 612 | muint_t off = mu_tbl_off(t); 613 | muint_t count = mu_tbl_count(t); 614 | mtbl(t)->len = 0; 615 | mtbl(t)->nils = 0; 616 | memset(mtbl(t)->array, 0, mu_tbl_size(t)); 617 | 618 | for (muint_t j = 0; j < i; j++) { 619 | if (!mtbl(t)->array[2*(j+off)+1]) { 620 | i++; 621 | } else { 622 | mu_tbl_insert(t, mtbl(t)->array[2*(j+off)+0], 623 | mtbl(t)->array[2*(j+off)+1]); 624 | } 625 | } 626 | 627 | mu_dec(mtbl(t)->array[2*(i+off)+0]); 628 | mu_t p = mtbl(t)->array[2*(i+off)+1]; 629 | 630 | for (muint_t j = i+1; j < count; j++) { 631 | mu_t k = mtbl(t)->array[2*(j+off)+0]; 632 | if (mu_isnum(k)) { 633 | k = mu_num_sub(k, mu_num_fromuint(1)); 634 | } 635 | 636 | mu_tbl_insert(t, k, mtbl(t)->array[2*(j+off)+1]); 637 | } 638 | 639 | return p; 640 | } 641 | } 642 | 643 | mu_t mu_tbl_concat(mu_t a, mu_t b, mu_t offset) { 644 | mu_assert(mu_istbl(a) && mu_istbl(b) 645 | && (!offset || mu_isnum(offset))); 646 | 647 | if (!offset) { 648 | offset = mu_num_fromuint(mu_tbl_getlen(a)); 649 | } else if (mu_num_cmp(offset, mu_num_fromuint(0)) < 0) { 650 | offset = mu_num_add(offset, mu_num_fromuint(mu_tbl_getlen(a))); 651 | } 652 | 653 | mu_t d = mu_tbl_create(mu_tbl_getlen(a) + mu_tbl_getlen(b)); 654 | mu_t k, v; 655 | 656 | for (muint_t i = 0; mu_tbl_next(a, &i, &k, &v);) { 657 | mu_tbl_insert(d, k, v); 658 | } 659 | 660 | for (muint_t i = 0; mu_tbl_next(b, &i, &k, &v);) { 661 | if (mu_isnum(k)) { 662 | mu_tbl_insert(d, mu_num_add(k, offset), v); 663 | } else { 664 | mu_tbl_insert(d, k, v); 665 | } 666 | } 667 | 668 | mu_dec(b); 669 | return d; 670 | } 671 | 672 | mu_t mu_tbl_subset(mu_t t, mint_t lower, mint_t upper) { 673 | mu_assert(mu_istbl(t)); 674 | lower = (lower >= 0) ? lower : lower + mu_tbl_getlen(t); 675 | upper = (upper >= 0) ? upper : upper + mu_tbl_getlen(t); 676 | 677 | if (lower < 0) { 678 | lower = 0; 679 | } 680 | 681 | if (upper > mtbl(t)->len) { 682 | upper = mtbl(t)->len; 683 | } 684 | 685 | if (lower >= upper) { 686 | mu_dec(t); 687 | return mu_tbl_create(0); 688 | } 689 | 690 | mu_t d = mu_tbl_create(upper - lower); 691 | 692 | muint_t i = 0; 693 | for (muint_t j = 0; j < lower; j++) { 694 | mu_tbl_next(t, &i, 0, 0); 695 | } 696 | 697 | for (muint_t j = lower; j < upper; j++) { 698 | mu_t k, v; 699 | mu_tbl_next(t, &i, &k, &v); 700 | if (mu_isnum(k)) { 701 | k = mu_num_sub(k, mu_num_fromuint(lower)); 702 | } 703 | 704 | mu_tbl_insert(d, k, v); 705 | } 706 | 707 | return d; 708 | } 709 | 710 | // Set operations 711 | mu_t mu_tbl_and(mu_t a, mu_t b) { 712 | mu_assert(mu_istbl(a) && mu_istbl(b)); 713 | mlen_t alen = mu_tbl_getlen(a); 714 | mlen_t blen = mu_tbl_getlen(b); 715 | mu_t d = mu_tbl_create(alen < blen ? alen : blen); 716 | mu_t k, v; 717 | 718 | for (muint_t i = 0; mu_tbl_next(a, &i, &k, &v);) { 719 | mu_t w = mu_tbl_lookup(b, mu_inc(k)); 720 | if (w) { 721 | mu_dec(w); 722 | mu_tbl_insert(d, k, v); 723 | } else { 724 | mu_dec(k); 725 | mu_dec(v); 726 | } 727 | } 728 | 729 | mu_dec(b); 730 | return d; 731 | } 732 | 733 | mu_t mu_tbl_or(mu_t a, mu_t b) { 734 | mu_assert(mu_istbl(a) && mu_istbl(b)); 735 | mu_t d = mu_tbl_create(mu_tbl_getlen(a) + mu_tbl_getlen(b)); 736 | mu_t k, v; 737 | 738 | for (muint_t i = 0; mu_tbl_next(b, &i, &k, &v);) { 739 | mu_tbl_insert(d, k, v); 740 | } 741 | 742 | for (muint_t i = 0; mu_tbl_next(a, &i, &k, &v);) { 743 | mu_tbl_insert(d, k, v); 744 | } 745 | 746 | mu_dec(b); 747 | return d; 748 | } 749 | 750 | mu_t mu_tbl_xor(mu_t a, mu_t b) { 751 | mu_assert(mu_istbl(a) && mu_istbl(b)); 752 | mlen_t alen = mu_tbl_getlen(a); 753 | mlen_t blen = mu_tbl_getlen(b); 754 | mu_t d = mu_tbl_create(alen > blen ? alen : blen); 755 | mu_t k, v; 756 | 757 | for (muint_t i = 0; mu_tbl_next(a, &i, &k, &v);) { 758 | mu_t w = mu_tbl_lookup(b, mu_inc(k)); 759 | if (!w) { 760 | mu_tbl_insert(d, k, v); 761 | } else { 762 | mu_dec(k); 763 | mu_dec(v); 764 | mu_dec(w); 765 | } 766 | } 767 | 768 | for (muint_t i = 0; mu_tbl_next(b, &i, &k, &v);) { 769 | mu_t w = mu_tbl_lookup(a, mu_inc(k)); 770 | if (!w) { 771 | mu_tbl_insert(d, k, v); 772 | } else { 773 | mu_dec(k); 774 | mu_dec(v); 775 | mu_dec(w); 776 | } 777 | } 778 | 779 | mu_dec(b); 780 | return d; 781 | } 782 | 783 | mu_t mu_tbl_diff(mu_t a, mu_t b) { 784 | mu_assert(mu_istbl(a) && mu_istbl(b)); 785 | mu_t d = mu_tbl_create(mu_tbl_getlen(a)); 786 | mu_t k, v; 787 | 788 | for (muint_t i = 0; mu_tbl_next(a, &i, &k, &v);) { 789 | mu_t w = mu_tbl_lookup(b, mu_inc(k)); 790 | if (!w) { 791 | mu_tbl_insert(d, k, v); 792 | } else { 793 | mu_dec(k); 794 | mu_dec(v); 795 | mu_dec(w); 796 | } 797 | } 798 | 799 | mu_dec(b); 800 | return d; 801 | } 802 | 803 | 804 | // String representation 805 | mu_t mu_tbl_parsen(const mbyte_t **ppos, const mbyte_t *end) { 806 | const mbyte_t *pos = *ppos; 807 | mu_t t = mu_tbl_create(0); 808 | mu_t i = mu_num_fromuint(0); 809 | 810 | if (*pos++ != '[') { 811 | return 0; 812 | } 813 | 814 | while (pos < end && *pos != ']') { 815 | mu_t k = mu_parsen(&pos, end); 816 | if (!k) { 817 | mu_dec(t); 818 | return 0; 819 | } 820 | 821 | if (pos < end && *pos == ':') { 822 | pos++; 823 | mu_t v = mu_parsen(&pos, end); 824 | if (!v) { 825 | mu_dec(k); 826 | mu_dec(t); 827 | return 0; 828 | } 829 | mu_tbl_insert(t, k, v); 830 | } else { 831 | mu_tbl_insert(t, i, k); 832 | i = mu_num_add(i, mu_num_fromuint(1)); 833 | } 834 | 835 | if (pos == end || *pos != ',') { 836 | break; 837 | } 838 | 839 | pos++; 840 | } 841 | 842 | if (pos == end || *pos++ != ']') { 843 | // unterminated table 844 | mu_dec(t); 845 | return 0; 846 | } 847 | 848 | *ppos = pos; 849 | return t; 850 | } 851 | 852 | mu_t mu_tbl_parse(const char *s, muint_t n) { 853 | const mbyte_t *pos = (const mbyte_t *)s; 854 | const mbyte_t *end = (const mbyte_t *)pos + n; 855 | 856 | mu_t t = mu_tbl_parsen(&pos, end); 857 | 858 | if (pos != end) { 859 | mu_dec(t); 860 | return 0; 861 | } 862 | 863 | return t; 864 | } 865 | 866 | static void mu_tbl_repr_nested(mu_t t, mu_t *s, muint_t *n, mu_t depth) { 867 | if (mu_num_cmp(depth, mu_num_fromuint(0)) <= 0) { 868 | mu_buf_pushf(s, n, "%t", t); 869 | return; 870 | } 871 | 872 | bool linear = mu_tbl_islist(t); 873 | for (muint_t i = 0; linear && i < mu_tbl_getlen(t); i++) { 874 | if (!mtbl(t)->array[i]) { 875 | linear = false; 876 | } 877 | } 878 | 879 | mu_buf_pushc(s, n, '['); 880 | 881 | mu_t k, v; 882 | for (muint_t i = 0; mu_tbl_next(t, &i, &k, &v);) { 883 | if (!linear) { 884 | mu_buf_pushf(s, n, "%r: ", k); 885 | } else { 886 | mu_dec(k); 887 | } 888 | 889 | if (mu_istbl(v)) { 890 | mu_tbl_repr_nested(v, s, n, mu_num_sub(depth, mu_num_fromuint(1))); 891 | mu_dec(v); 892 | } else { 893 | mu_buf_pushf(s, n, "%r", v); 894 | } 895 | mu_buf_pushcstr(s, n, ", "); 896 | } 897 | 898 | if (mu_tbl_getlen(t) > 0) { 899 | *n -= 2; 900 | } 901 | 902 | mu_buf_pushc(s, n, ']'); 903 | } 904 | 905 | mu_t mu_tbl_repr(mu_t t, mu_t depth) { 906 | mu_assert(mu_istbl(t) && (!depth || mu_isnum(depth))); 907 | if (!depth) { 908 | depth = mu_num_fromuint(1); 909 | } else if (depth == mu_num_fromuint(0)) { 910 | return mu_str_format("", (muint_t)t & ~7); 911 | } 912 | 913 | mu_t s = mu_buf_create(0); 914 | muint_t n = 0; 915 | 916 | mu_tbl_repr_nested(t, &s, &n, depth); 917 | 918 | return mu_str_intern(s, n); 919 | } 920 | 921 | 922 | // Table related Mu functions 923 | static mcnt_t mu_tbl_bfn(mu_t *frame) { 924 | mu_t tail = frame[1]; 925 | mu_checkargs(!tail || mu_istbl(tail) || mu_isbuf(tail), 926 | MU_TBL_KEY, 0x2, frame); 927 | 928 | mu_t m = mu_tbl_frommu(mu_inc(frame[0])); 929 | mu_checkargs(m, MU_TBL_KEY, 0x2, frame); 930 | mu_dec(frame[0]); 931 | frame[0] = m; 932 | 933 | if (mu_istbl(tail)) { 934 | mu_tbl_settail(frame[0], tail); 935 | } else { 936 | mu_tbl_settail(frame[0], mu_buf_gettail(tail)); 937 | mu_dec(tail); 938 | } 939 | 940 | return 1; 941 | } 942 | 943 | MU_DEF_STR(mu_tbl_key_def, "tbl") 944 | MU_DEF_BFN(mu_tbl_def, 0x2, mu_tbl_bfn) 945 | --------------------------------------------------------------------------------