From 10a53146462bf1cebeab4218d818f0023306ca50 Mon Sep 17 00:00:00 2001 From: Shaw Summa Date: Wed, 23 Oct 2024 06:30:06 -0400 Subject: [PATCH] add lr parser Signed-off-by: Shaw Summa --- js.txt | 26 + lua.txt | 72 +++ makefile | 9 +- test/lua/parser/lr1.js | 208 ++++++++ test/lua/parser/lr1.lua | 469 ++++++++++++++++++ test/lua/tables/test.lua | 2 +- .../tables/{trees2.lua => trees-basic.lua} | 2 +- test/lua/tables/trees-lambda.lua | 1 + test/lua/tables/trees-named.lua | 1 + test/lua/tables/trees-no-len.lua | 58 +++ .../{trees_no_loop.lua => trees-no-loop.lua} | 0 test/lua/tables/trees.lua | 1 + vendor/mimalloc | 2 +- vm/ast/comp.c | 11 +- vm/gc.c | 52 +- vm/io.c | 27 +- vm/lib.h | 10 + vm/lua/repl.c | 11 +- vm/obj.c | 105 ++-- vm/obj.h | 3 - vm/std.c | 141 ++---- vm/vm.h | 20 +- 22 files changed, 994 insertions(+), 237 deletions(-) create mode 100644 js.txt create mode 100644 lua.txt create mode 100644 test/lua/parser/lr1.js create mode 100644 test/lua/parser/lr1.lua rename test/lua/tables/{trees2.lua => trees-basic.lua} (93%) create mode 100644 test/lua/tables/trees-no-len.lua rename test/lua/tables/{trees_no_loop.lua => trees-no-loop.lua} (100%) diff --git a/js.txt b/js.txt new file mode 100644 index 00000000..e82d7c30 --- /dev/null +++ b/js.txt @@ -0,0 +1,26 @@ +{ + action: [ + Map { 'S' => 's1', 'X' => 's2', 'a' => 's3', 'b' => 's4' }, + Map { '$' => 'acc' }, + Map { 'X' => 's5', 'a' => 's6', 'b' => 's7' }, + Map { 'X' => 's8', 'a' => 's3', 'b' => 's4' }, + Map { 'b' => 'r3', 'a' => 'r3' }, + Map { '$' => 'r1' }, + Map { 'X' => 's9', 'a' => 's6', 'b' => 's7' }, + Map { '$' => 'r3' }, + Map { 'b' => 'r2', 'a' => 'r2' }, + Map { '$' => 'r2' } + ], + goTo: [ + Map { 'S' => 1, 'X' => 2 }, + Map {}, + Map { 'X' => 5 }, + Map { 'X' => 8 }, + Map {}, + Map {}, + Map { 'X' => 9 }, + Map {}, + Map {}, + Map {} + ] +} diff --git a/lua.txt b/lua.txt new file mode 100644 index 00000000..1a4a7226 --- /dev/null +++ b/lua.txt @@ -0,0 +1,72 @@ +{ + go_to = [ + { + S = 2 + X = 3 + } + { + } + { + X = 6 + } + { + X = 9 + } + { + } + { + } + { + X = 10 + } + { + } + { + } + { + } + ] + action = [ + { + S = s2 + b = s5 + a = s4 + X = s3 + } + { + $ = acc + } + { + b = s8 + a = s7 + X = s6 + } + { + b = s5 + a = s4 + X = s9 + } + { + a = r4 + b = r4 + } + { + $ = r2 + } + { + b = s8 + a = s7 + X = s10 + } + { + $ = r4 + } + { + a = r3 + b = r3 + } + { + $ = r3 + } + ] +} diff --git a/makefile b/makefile index 900dd1d4..b7e821bf 100644 --- a/makefile +++ b/makefile @@ -2,7 +2,7 @@ # Must be a GCC or Clang CC ?= cc -OPT ?= -O3 -ffast-math -flto -DNDEBUG +OPT ?= -O3 -fno-math-errno -fno-trapping-math -flto -DNDEBUG EXE ?= @@ -19,15 +19,10 @@ LIBM_FLAGS := ${LIBM_${LIBM}} BASE_CFLAGS := ${OPT} -Ivendor/tree-sitter/lib/include -Ivendor/mimalloc/include -Ivendor/tree-sitter/lib/src ${CFLAGS} BASE_LDFLAGS := ${OPT} ${LDFLAGS} ${LIBM_FLAGS} -# mimalloc - -# BASE_LDFLAGS += -lSynchronization -MI_PRIM_SRC := vendor/mimalloc/src/prim/unix/prim.c - # object files and depends MAIN_SRCS = main/minivm.c VM_SRCS := $(shell find vm | grep \\.c) -MI_SRCS := ${MI_PRIM_SRC} vendor/mimalloc/src/alloc-posix.c vendor/mimalloc/src/alloc-aligned.c vendor/mimalloc/src/alloc.c vendor/mimalloc/src/arena.c vendor/mimalloc/src/bitmap.c vendor/mimalloc/src/heap.c vendor/mimalloc/src/init.c vendor/mimalloc/src/libc.c vendor/mimalloc/src/options.c vendor/mimalloc/src/os.c vendor/mimalloc/src/page.c vendor/mimalloc/src/random.c vendor/mimalloc/src/segment-map.c vendor/mimalloc/src/segment.c vendor/mimalloc/src/stats.c +# MI_SRCS := vendor/mimalloc/src/prim/prim.c vendor/mimalloc/src/alloc-posix.c vendor/mimalloc/src/alloc-aligned.c vendor/mimalloc/src/alloc.c vendor/mimalloc/src/arena.c vendor/mimalloc/src/bitmap.c vendor/mimalloc/src/heap.c vendor/mimalloc/src/init.c vendor/mimalloc/src/libc.c vendor/mimalloc/src/options.c vendor/mimalloc/src/os.c vendor/mimalloc/src/page.c vendor/mimalloc/src/random.c vendor/mimalloc/src/segment-map.c vendor/mimalloc/src/segment.c vendor/mimalloc/src/stats.c TS_SRCS += vendor/tree-sitter/lib/src/alloc.c vendor/tree-sitter/lib/src/get_changed_ranges.c vendor/tree-sitter/lib/src/language.c vendor/tree-sitter/lib/src/lexer.c vendor/tree-sitter/lib/src/node.c vendor/tree-sitter/lib/src/parser.c vendor/tree-sitter/lib/src/query.c vendor/tree-sitter/lib/src/stack.c vendor/tree-sitter/lib/src/subtree.c vendor/tree-sitter/lib/src/tree_cursor.c vendor/tree-sitter/lib/src/tree.c vendor/tree-sitter/lib/src/wasm_store.c IC_SRCS := vendor/isocline/src/isocline.c MAIN_SRCS += ${VM_SRCS} ${TS_SRCS} ${IC_SRCS} ${MI_SRCS} diff --git a/test/lua/parser/lr1.js b/test/lua/parser/lr1.js new file mode 100644 index 00000000..14847a7e --- /dev/null +++ b/test/lua/parser/lr1.js @@ -0,0 +1,208 @@ +function first(G, A) { + let result = new Set + let visited = new Set + let stack = [A] + while (stack.length > 0) { + let X = stack.pop() + if (visited.has(X)) continue + visited.add(X) + if (!/^[A-Z]/.test(X) || X === '$') { + result.add(X) + continue + } + for (let i = 0; i < G.length; i++) { + let r = G[i] + if (r[0] === X && r[1] !== X) { + stack.push(r[1]) + } + } + } + return result +} + +function closure(G, items) { + let stack = items.slice() + let state = items.slice() + let visited = new Set + while (true) { + if (stack.length === 0) break + let item = stack.shift() + let key = item.rule + ',' + item.dot + ',' + item.lookahead + if (visited.has(key)) { + continue + } + visited.add(key) + state.push(item) + let r = G[item.rule] + let X1 = r[item.dot + 1] + let X2 = r[item.dot + 2] + for (let i = 0; i < G.length; i++) { + if (G[i][0] !== X1) continue + let ls = item.dot + 2 === r.length + ? new Set([item.lookahead]) + : union(first(G, X1), first(G, X2)) + for (let lookahead of ls) { + let nitem = { + rule: i, + dot: 0, + lookahead, + next: -1, + index: -1, + } + stack.push(nitem) + } + } + } + return state +} + +function union(A, B) { + // :( + return new Set(Array.from(A).concat(Array.from(B))) +} + +class States { + static key(items) { + return items.map(item => { + return item.rule + ',' + item.dot + ',' + item.lookahead + }).sort().join('_') + } + constructor(G) { + this.G = G + this.states = [] + this._stateKeys = new Map + } + add(items) { + let key = States.key(items) + + let i = this._stateKeys.get(key) + if (i !== undefined) return i + i = this.states.length + this.states.push(items) + this._stateKeys.set(key, i) + return i + } + has(items) { + return this._stateKeys.has(States.key(items)) + } +} + +function groupNext(G, state) { + let groups = new Map + for (let i = 0; i < state.length; i++) { + let s = state[i] + let rule = G[s.rule] + if (s.dot + 1 >= rule.length) continue + let X0 = rule[0] + let X1 = rule[s.dot + 1] + let gs = groups.get(X1) + if (gs == null) gs = [] + gs.push({ + rule: s.rule, + dot: s.dot + 1, + lookahead: s.lookahead, + index: i, + next: -1, + }) + groups.set(X1, gs) + } + return groups +} + +function itemSets(G) { + let states = new States(G) + let I0 = closure(G, [{ rule: 0, dot: 0, lookahead: '$', index: 0, next: -1 }]) + let i0 = states.add(I0) + let stack = [I0] + while (true) { + if (stack.length === 0) break + let I = stack.shift() + let groups = groupNext(G, I) + for (let T of Array.from(groups.keys()).sort()) { + let gs = groups.get(T) + let J = closure(G, gs) + if (!states.has(J)) stack.push(J) + let j = states.add(J) + for (let si = 0; si < gs.length; si++) { + let g = gs[si] + I[g.index].next = j + } + } + } + return states.states +} + +function createTable(G, states) { + let action = Array(states.length).fill(null).map(x => new Map) + let goTo = Array(states.length).fill(null).map(x => new Map) + + for (let i = 0; i < states.length; i++) { + let I = states[i] + for (let j = 0; j < I.length; j++) { + let item = I[j] + if (item.rule === 0 && item.dot + 1 === G[item.rule].length && item.lookahead === '$') { + action[i].set('$', 'acc') + } else if (item.dot + 1 === G[item.rule].length) { + let a = item.lookahead + action[i].set(a, 'r' + item.rule) + } else { + let a = G[item.rule][item.dot + 1] + action[i].set(a, 's' + item.next) + } + let A = G[item.rule][item.dot + 1] + if (/^[A-Z]/.test(A)) { + goTo[i].set(A, item.next) + } + } + } + return { action, goTo } +} + +function parse(G, { action, goTo }, input) { + let firstSymbol = G[0][0] + let offset = 0 + let stack = [0] + let nodes = [] + let lookahead = input[0] + + while (true) { + let state = stack[stack.length - 1] + let a = action[state].get(lookahead) + if (a === undefined) throw new Error(`no action for state: ${state} lookahead: ${lookahead}`) + let n = Number(a.slice(1)) + if (/^s/.test(a)) { + nodes.push({ symbol: lookahead, offset }) + stack.push(n) + lookahead = input[++offset] + } else if (/^r/.test(a)) { + let symbol = G[n][0] + let arity = G[n].length - 1 + let children = Array(arity) + for (let i = 0; i < arity; i++) { + children[arity - 1 - i] = nodes.pop() + stack.pop() + } + nodes.push({ symbol, children }) + + state = stack[stack.length - 1] + let gt = goTo[state].get(symbol) + if (gt === undefined) throw new Error(`undefined goto for state=${state} symbol=${symbol}`) + stack.push(gt) + } else if (a === 'acc') { + return { symbol: firstSymbol, children: nodes } + } else { + throw new Error(`unexpected value for action ${a}`) + } + } +} + +let grammar = [ + [ "S", "S" ], + [ "S", "X", "X" ], + [ "X", "a", "X" ], + [ "X", "b" ] +] +let sets = itemSets(grammar) +// console.log(sets) +let tab = createTable(grammar, sets) +console.log(tab) diff --git a/test/lua/parser/lr1.lua b/test/lua/parser/lr1.lua new file mode 100644 index 00000000..65e667cf --- /dev/null +++ b/test/lua/parser/lr1.lua @@ -0,0 +1,469 @@ + + +local tag = {} +if not vm then + vm = {} + + function vm.concat(...) + local r = {} + for i=1, select('#', ...) do + r[i] = tostring(select(i, ...)) + end + return table.concat(r) + end + + local function debug(pre, ind, val, done) + if type(val) == 'table' then + if done[val] then + print(ind .. pre .. '...') + else + done[val] = true + if val[tag] == 'array' then + print(ind .. pre .. '[') + for k=1, val.len do + debug('', ind .. ' ', val[k], done) + end + print(ind .. ']') + else + print(ind .. pre .. '{') + for k,v in pairs(val) do + if type(v) ~= 'function' then + debug(tostring(k) .. ' = ', ind .. ' ', v, done) + end + end + print(ind .. '}') + end + done[val] = false + end + else + print(ind .. pre .. tostring(val)) + end + end + + function vm.print(x) + debug('', '', x, {}) + end +end + +local function array(r) + local t = {} + + t[tag] = 'array' + + t.len = 0 + + function t.pop() + local r = t[t.len] + t.len = t.len - 1 + return r + end + + function t.push(v) + t.len = t.len + 1 + t[t.len] = v + end + + function t.shift() + local ret = t[1] + for i=2, t.len do + t[i-1] = t[i] + end + t[t.len] = nil + t.len = t.len - 1 + return ret + end + + function t.sorted() + local r = {} + for i=1, t.len do + local want = 1 + local value = t[i] + while want < i and r[want] > value do + want = want + 1 + end + for j=want, i do + local next_value = r[j] + r[j] = value + value = next_value + end + end + return array(r) + end + + function t.join(j) + local r = '' + for i=1, t.len do + if i == 1 then + r = t[i] + else + r = vm.concat(r, j, t[i]) + end + end + return r + end + + for i=1, #r do + t.push(r[i]) + end + + return t +end + +local function set(d) + local s = {} + local data = {} + s.keys = array {} + + function s.add(v) + if not s.has(v) then + data[v] = true + s.keys.push(v) + end + end + + function s.union(o) + local r = set {} + + for i=1, s.keys.len do + r.add(s.keys[i]) + end + + for i=1, o.keys.len do + r.add(o.keys[i]) + end + + return r + end + + function s.has(k) + if data[k] then + return true + else + return false + end + end + + function s.eq(o) + if s.keys.len ~= o.keys.len then + return false + end + for i=1, s.keys.len do + if not o.has(s.keys[i]) then + return false + end + end + return true + end + + for i=1, #d do + s.add(d[i]) + end + + return s +end + +local function first(g, A) + local result = set {} + local visited = set {} + local stack = array {A} + + while stack.len ~= 0 do + local x = stack.pop() + if not visited.has(x) then + visited.add(x) + local first_x = string.sub(x, 1, 1) + if not ('A' <= first_x and first_x <= 'Z') or x == '$' then + result.add(x) + else + for i=1, g.len do + local r = g[i] + if r[1] == x and r[2] ~= x then + stack.push(r[2]) + end + end + end + end + end + + return result +end + +local function dup(items) + local r = array {} + for i=1, items.len do + r.push(items[i]) + end + return r +end + +local function closure(g, items) + local stack = dup(items) + local state = dup(items) + local visited = set {} + + while stack.len ~= 0 do + local item = stack.shift() + local key = vm.concat(tostring(item.rule), ',', tostring(item.dot), ',', tostring(item.lookahead)) + if not visited.has(key) then + visited.add(key) + state.push(item) + local r = g[item.rule] + local x1 = r[item.dot + 1] + local x2 = r[item.dot + 2] + for i=1, g.len do + if g[i][1] == x1 then + local ls = nil + + if x2 then + ls = first(g, x1).union(first(g, x2)) + else + ls = set {item.lookahead} + end + + for j=1, ls.keys.len do + stack.push { + rule = i, + dot = 1, + lookahead = ls.keys[j], + next = -1, + index = -1, + } + local key = vm.concat(tostring(i), ',', '1', ',', ls.keys[j]) + end + end + end + end + end + + return state +end + +local function key(items) + local t = set {} + for i=1, items.len do + local item = items[i] + t.add(vm.concat(tostring(item.rule), ',', tostring(item.dot), ',', tostring(item.lookahead))) + end + return t.keys.sorted().join('_') +end + +local function states(g) + local obj = {} + + obj.g = g + obj.states = array {} + + local keys = {} + + function obj.add(items) + local key = key(items) + if not keys[key] then + obj.states.push(items) + keys[key] = obj.states.len + end + return keys[key] + end + + function obj.has(items) + if keys[key(items)] then + return true + else + return false + end + end + + return obj +end + +local function group_next(g, state) + local groups = { + map = {}, + set = set {}, + } + + for i=1, state.len do + local s = state[i] + local rule = g[s.rule] + local x1 = rule[s.dot + 1] + if x1 then + local gs = groups.map[x1] or array {} + + gs.push { + rule = s.rule, + dot = s.dot + 1, + lookahead = s.lookahead, + index = i, + next = -1, + } + + groups.map[x1] = gs + groups.set.add(x1) + end + end + + return groups +end + +local function item_sets(g) + local states = states(g) + + local i0v = { + rule = 1, + dot = 1, + lookahead = '$', + index = 1, + next = -1, + } + local i0 = closure(g, array { i0v }) + states.add(i0) + local stack = array { i0 } + + while stack.len ~= 0 do + local i = stack.shift() + local groups = group_next(g, i) + for j=1, groups.set.keys.len do + local t = groups.set.keys[j] + local gs = groups.map[t] + local j = closure(g, gs) + if not states.has(j) then + stack.push(j) + end + j = states.add(j) + for si=1, gs.len do + local g = gs[si] + i[g.index].next = j + end + end + end + + return states.states +end + +local function make_table(g, states) + local action = array {} + local go_to = array {} + for i=1, states.len do + action.push({}) + go_to.push({}) + end + + for i=1, states.len do + local s = states[i] + for j=1, s.len do + local item = s[j] + local gi = g[item.rule] + if item.rule == 1 + and item.dot == gi.len + and item.lookahead == '$' then + action[i]['$'] = 'acc' + elseif item.dot == gi.len then + local a = item.lookahead + action[i][a] = vm.concat('r', item.rule) + else + action[i][gi[item.dot + 1]] = vm.concat('s', item.next) + end + local a = gi[item.dot + 1] + if a then + local first_a = string.sub(a, 1, 1) + if 'A' <= first_a and first_a <= 'Z' then + go_to[i][a] = item.next + end + end + end + end + + return { + action = action, + go_to = go_to, + } +end + +local function parse(g, ag, input) + local action = ag.action + local go_to = ag.go_to + + local first_symbol = g[1][1] + local offset = 1 + local stack = array { 1 } + local nodes = array {} + local lookahead = input[1] or '$' + + while true do + local state = stack[stack.len] + local a = action[state][lookahead] + if not a then + print('bad job; you did an error... #1') + end + + local n = tonumber(string.sub(a, 2)) + local char0 = string.sub(a, 1, 1) + if char0 == 's' then + nodes.push { + symbol = lookahead, + offset = offset, + } + + stack.push(n) + offset = offset + 1 + lookahead = input[offset] or '$' + elseif char0 == 'r' then + local symbol = g[n][1] + local arity = g[n].len - 1 + local children = array {} + for i=1, arity do + children.push(nodes[nodes.len - arity + i]) + stack.pop() + end + for i=1, arity do + nodes.pop() + end + nodes.push { + symbol = symbol, + children = children, + } + state = stack[stack.len] + local gt = go_to[state][symbol] + + if not gt then + print('bad job; you did an error... #2') + end + + stack.push(gt) + elseif a == 'acc' then + return { + symbol = first_symbol, + children = nodes, + } + else + print('bad job; you did an error... #3') + end + end +end + +local function format(ast) + if ast.children then + local parts = array {} + parts.push(ast.symbol) + for i=1, ast.children.len do + parts.push(format(ast.children[i])) + end + return vm.concat('(', parts.join(' '), ')') + else + return ast.symbol + end +end + +local grammar = array { + array { 'S', 'S' }, + array { 'S', 'X', 'X' }, + array { 'X', 'a', 'X' }, + array { 'X', 'b' }, +} + +local input = array { 'a', 'a', 'b', 'b' } + +local sets = item_sets(grammar) +local tab = make_table(grammar, sets) +local ast = parse(grammar, tab, input) + +print(format(ast)) diff --git a/test/lua/tables/test.lua b/test/lua/tables/test.lua index 01f83b36..190d706d 100644 --- a/test/lua/tables/test.lua +++ b/test/lua/tables/test.lua @@ -19,4 +19,4 @@ local function ItemCheck(tree) end local stretchtree = BottomUpTree(0, 12) -print(ItemCheck(stretchtree)) +print(stretchdepth, ItemCheck(stretchtree)) diff --git a/test/lua/tables/trees2.lua b/test/lua/tables/trees-basic.lua similarity index 93% rename from test/lua/tables/trees2.lua rename to test/lua/tables/trees-basic.lua index 68156ff6..bfd4c8af 100644 --- a/test/lua/tables/trees2.lua +++ b/test/lua/tables/trees-basic.lua @@ -24,4 +24,4 @@ local function ItemCheck(tree) end local stretchtree = BottomUpTree(0, 3) -print(ItemCheck(stretchtree)) +print(stretchdepth, ItemCheck(stretchtree)) diff --git a/test/lua/tables/trees-lambda.lua b/test/lua/tables/trees-lambda.lua index c16f0dd9..03be9bfe 100644 --- a/test/lua/tables/trees-lambda.lua +++ b/test/lua/tables/trees-lambda.lua @@ -49,6 +49,7 @@ local maxdepth = tonumber(arg and arg[1]) or 12 local stretchdepth = maxdepth + 1 local stretchtree = BottomUpTree(0, stretchdepth) +print(stretchdepth, ItemCheck(stretchtree)) local longlivedtree = BottomUpTree(0, maxdepth) diff --git a/test/lua/tables/trees-named.lua b/test/lua/tables/trees-named.lua index 8136c19e..f86d3ccc 100644 --- a/test/lua/tables/trees-named.lua +++ b/test/lua/tables/trees-named.lua @@ -41,6 +41,7 @@ local maxdepth = tonumber(arg and arg[1]) or 14 local stretchdepth = maxdepth + 1 local stretchtree = BottomUpTree(0, stretchdepth) +print(stretchdepth, ItemCheck(stretchtree)) local longlivedtree = BottomUpTree(0, maxdepth) diff --git a/test/lua/tables/trees-no-len.lua b/test/lua/tables/trees-no-len.lua new file mode 100644 index 00000000..034fa4af --- /dev/null +++ b/test/lua/tables/trees-no-len.lua @@ -0,0 +1,58 @@ +-- The Computer Language Benchmarks Game +-- http://benchmarksgame.alioth.debian.org/ +-- contributed by Mike Pall +local function BottomUpTree(item, depth) + if depth > 0 then + local i = item + item + depth = depth - 1 + local left = BottomUpTree(i - 1, depth) + local right = BottomUpTree(i, depth) + return {item, left, right} + else + return {item} + end +end + +local function ItemCheck(tree) + local t2 = tree[2] + if t2 then + return tree[1] + ItemCheck(t2) - ItemCheck(tree[3]) + else + return tree[1] + end +end + +local function pow2(n) + if n == 0 then + return 1 + else + return pow2(n - 1) * 2 + end +end + +local mindepth = 4 +local maxdepth = tonumber(arg and arg[1]) or 16 + +local stretchdepth = maxdepth + 1 + +local stretchtree = BottomUpTree(0, stretchdepth) +print(stretchdepth, ItemCheck(stretchtree)) + +local longlivedtree = BottomUpTree(0, maxdepth) + +local depth = mindepth +while depth <= maxdepth do + local iterations = pow2(maxdepth - depth + mindepth) + local check = 0 + local i = 1 + while i <= iterations do + local x = ItemCheck(BottomUpTree(1, depth)) + check = check + x + ItemCheck(BottomUpTree(-1, depth)) + i = i + 1 + end + print(depth, check) + depth = depth + 2 + -- if vm then vm.gc() end +end + +print(maxdepth, ItemCheck(longlivedtree)) diff --git a/test/lua/tables/trees_no_loop.lua b/test/lua/tables/trees-no-loop.lua similarity index 100% rename from test/lua/tables/trees_no_loop.lua rename to test/lua/tables/trees-no-loop.lua diff --git a/test/lua/tables/trees.lua b/test/lua/tables/trees.lua index 770266e3..e1bbd421 100644 --- a/test/lua/tables/trees.lua +++ b/test/lua/tables/trees.lua @@ -35,6 +35,7 @@ local maxdepth = tonumber(arg and arg[1]) or 16 local stretchdepth = maxdepth + 1 local stretchtree = BottomUpTree(0, stretchdepth) +print(stretchdepth, ItemCheck(stretchtree)) local longlivedtree = BottomUpTree(0, maxdepth) diff --git a/vendor/mimalloc b/vendor/mimalloc index db3d8485..e55ae0ae 160000 --- a/vendor/mimalloc +++ b/vendor/mimalloc @@ -1 +1 @@ -Subproject commit db3d8485d2f45a6f179d784f602f9eff4f60795c +Subproject commit e55ae0aeb76f5205edce57b97031be6aa80f962a diff --git a/vm/ast/comp.c b/vm/ast/comp.c index 91b953d6..b81fefcd 100644 --- a/vm/ast/comp.c +++ b/vm/ast/comp.c @@ -4,6 +4,7 @@ #include "build.h" #include "print.h" #include "../gc.h" +#include "../errors.h" struct vm_ast_comp_t; typedef struct vm_ast_comp_t vm_ast_comp_t; @@ -1027,14 +1028,8 @@ vm_ir_block_t *vm_ast_comp_more(vm_t *vm, vm_ast_node_t node) { ); vm_ir_arg_t result_arg = vm_ast_comp_to_raw(&comp, node); if (result_arg.type == VM_IR_ARG_TYPE_ERROR) { - for (vm_error_t *error = result_arg.error; error != NULL; error = error->child) { - if (error->child != NULL) { - fprintf(stderr, "range: %zu .. %zu\n", error->range.start.byte, error->range.stop.byte); - } else { - fprintf(stderr, "error: %s\n", error->msg); - break; - } - } + vm_error_report(result_arg.error, stderr); + return NULL; } vm_ast_comp_names_t *names = vm_ast_comp_names_pop(&comp); vm_ast_names_free(names); diff --git a/vm/gc.c b/vm/gc.c index 62c280c0..e1e92f41 100644 --- a/vm/gc.c +++ b/vm/gc.c @@ -1,7 +1,6 @@ #include "gc.h" #include "ir.h" -#include "primes.inc" struct vm_gc_objs_t; struct vm_gc_t; @@ -40,7 +39,7 @@ struct vm_gc_t { } block; } by_type; } stats; - #endif +#endif }; static inline void vm_gc_objs_add(vm_gc_objs_t *restrict objs, vm_obj_t obj) { @@ -88,10 +87,8 @@ static inline void vm_gc_mark_obj(vm_obj_t obj) { if (!table->mark) { table->mark = true; uint32_t len = vm_primes_table[table->size]; - vm_table_pair_t *pairs = table->pairs; - for (uint32_t i = 0; i < len; i++) { - vm_gc_mark_obj(pairs[i].key); - vm_gc_mark_obj(pairs[i].value); + for (uint32_t i = 0; i < len * 2; i++) { + vm_gc_mark_obj(table->entries[i]); } } } else if (vm_obj_is_closure(obj)) { @@ -113,7 +110,7 @@ void vm_gc_mark(vm_t *vm, vm_obj_t *top) { vm_gc_mark_block(blocks->block); } vm_gc_mark_obj(vm->std); - for (vm_obj_t *head = vm->base; head < top; head++) { + for (vm_obj_t *restrict head = vm->base; head < top; head++) { vm_gc_mark_obj(*head); } } @@ -144,7 +141,7 @@ void vm_gc_sweep(vm_t *vm) { } else if (vm_obj_is_table(obj)) { vm_obj_table_t *table = vm_obj_get_table(obj); if (!table->mark) { - vm_free(table->pairs); + vm_free(table->entries); vm_free(table); } else { table->mark = false; @@ -184,39 +181,40 @@ void vm_gc_sweep(vm_t *vm) { } } } - // printf("\n"); - // printf("--- gc#%zu: %f%% keep ---\n", gc->runs, (double) write / gc->objs.len * 100.0); - // printf("strings: %zu\n", gc->stats.by_type.string.count); - // printf("tables: %zu\n", gc->stats.by_type.table.count); - // printf("closures: %zu\n", gc->stats.by_type.closure.count); - // printf("blocks: %zu\n", gc->stats.by_type.block.count); - // printf("\n"); +#if VM_GC_STATS && VM_GC_STATS_DEBUG + printf("--- gc#%zu: %f%% keep ---\n", gc->runs, (double) write / gc->objs.len * 100.0); + printf("strings: %zu\n", gc->stats.by_type.string.count); + printf("tables: %zu\n", gc->stats.by_type.table.count); + printf("closures: %zu\n", gc->stats.by_type.closure.count); + printf("blocks: %zu\n", gc->stats.by_type.block.count); + printf("\n"); +#endif gc->objs.len = write; size_t next = write * VM_GC_FACTOR; - // if (next >= gc->last) { + if (next >= gc->last) { gc->last = next; - // } + } } vm_obj_table_t *vm_table_new(vm_t *vm) { - vm_obj_table_t *ret = vm_malloc(sizeof(vm_obj_table_t)); -#if VM_EMPTY_BYTE == 0 - ret->pairs = vm_calloc(sizeof(vm_table_pair_t) * vm_primes_table[0]); -#else - ret->pairs = vm_malloc(sizeof(vm_table_pair_t) * vm_primes_table[0]); - memset(ret->pairs, VM_EMPTY_BYTE, sizeof(vm_table_pair_t) * vm_primes_table[0]); -#endif + vm_obj_table_t *restrict ret = vm_malloc(sizeof(vm_obj_table_t)); ret->size = 0; ret->used = 0; ret->len = 0; ret->mark = false; +#if VM_EMPTY_BYTE == 0 + ret->entries = vm_calloc(sizeof(vm_obj_t) * vm_primes_table[ret->size] * 2); +#else + ret->entries = vm_malloc(sizeof(vm_obj_t) * vm_primes_table[ret->size] * 2); + memset(ret->entries, VM_EMPTY_BYTE, sizeof(vm_obj_t) * vm_primes_table[ret->size] * 2); +#endif vm_gc_add(vm, vm_obj_of_table(ret)); return ret; } void vm_gc_run(vm_t *vm, vm_obj_t *top) { vm_gc_t *restrict gc = vm->gc; - if (gc->last >= gc->objs.len) { + if (gc->last >= gc->objs.len || VM_GC_DISABLED) { return; } gc->runs += 1; @@ -225,11 +223,11 @@ void vm_gc_run(vm_t *vm, vm_obj_t *top) { } void vm_gc_init(vm_t *vm) { - vm->gc = vm_malloc(sizeof(vm_gc_t)); - vm_gc_t *restrict gc = vm->gc; + vm_gc_t *gc = vm_malloc(sizeof(vm_gc_t)); *gc = (vm_gc_t){ .last = VM_GC_MIN, }; + vm->gc = gc; } void vm_gc_deinit(vm_t *vm) { diff --git a/vm/io.c b/vm/io.c index a1897c92..64817ed2 100644 --- a/vm/io.c +++ b/vm/io.c @@ -2,7 +2,6 @@ #include "io.h" #include "ir.h" #include "math.h" -#include "primes.inc" void vm_io_buffer_vformat(vm_io_buffer_t *buf, const char *fmt, va_list ap) { if (buf->buf == NULL) { @@ -168,31 +167,31 @@ void vm_io_buffer_obj_debug(vm_io_buffer_t *out, size_t indent, const char *pref vm_io_buffer_format(out, "table(%p) {\n", tab); size_t len = vm_primes_table[tab->size]; for (size_t i = 0; i < len; i++) { - vm_table_pair_t p = tab->pairs[i]; - if (vm_obj_is_nil(p.key)) { + vm_obj_t key = tab->entries[i]; + if (vm_obj_is_nil(key)) { // no print for empty keys - } else if (vm_obj_is_boolean(p.key)) { + } else if (vm_obj_is_boolean(key)) { if (vm_obj_get_boolean(value)) { - vm_io_buffer_obj_debug(out, indent + 1, "[[true]] = ", p.value, &next); + vm_io_buffer_obj_debug(out, indent + 1, "[[true]] = ", tab->entries[vm_primes_table[tab->size] + i], &next); } else { - vm_io_buffer_obj_debug(out, indent + 1, "[[false]] = ", p.value, &next); + vm_io_buffer_obj_debug(out, indent + 1, "[[false]] = ", tab->entries[vm_primes_table[tab->size] + i], &next); } - } else if (vm_obj_is_number(p.key)) { + } else if (vm_obj_is_number(key)) { char buf[64]; - snprintf(buf, 63, "[[" VM_FORMAT_FLOAT "]] = ", vm_obj_get_number(p.key)); - vm_io_buffer_obj_debug(out, indent + 1, buf, p.value, &next); + snprintf(buf, 63, "[[" VM_FORMAT_FLOAT "]] = ", vm_obj_get_number(key)); + vm_io_buffer_obj_debug(out, indent + 1, buf, tab->entries[vm_primes_table[tab->size] + i], &next); } - else if (vm_obj_is_string(p.key)) { + else if (vm_obj_is_string(key)) { vm_io_buffer_t *buf = vm_io_buffer_new(); - vm_io_buffer_format(buf, "%s = ", vm_obj_get_string(p.key)->buf); - vm_io_buffer_obj_debug(out, indent + 1, buf->buf, p.value, &next); + vm_io_buffer_format(buf, "%s = ", vm_obj_get_string(key)->buf); + vm_io_buffer_obj_debug(out, indent + 1, buf->buf, tab->entries[vm_primes_table[tab->size] + i], &next); vm_free(buf->buf); vm_free(buf); } else { vm_io_indent(out, indent + 1, ""); vm_io_buffer_format(out, "pair {\n"); - vm_io_buffer_obj_debug(out, indent + 2, "key = ", p.key, &next); - vm_io_buffer_obj_debug(out, indent + 2, "val = ", p.value, &next); + vm_io_buffer_obj_debug(out, indent + 2, "key = ", key, &next); + vm_io_buffer_obj_debug(out, indent + 2, "val = ", tab->entries[vm_primes_table[tab->size] + i], &next); vm_io_indent(out, indent + 1, ""); vm_io_buffer_format(out, "}\n"); } diff --git a/vm/lib.h b/vm/lib.h index cbf52530..c7693054 100644 --- a/vm/lib.h +++ b/vm/lib.h @@ -54,10 +54,20 @@ #include "../vendor/mimalloc/include/mimalloc.h" +#if VM_MALLOC_MI #define vm_malloc(x) mi_malloc(x) #define vm_calloc(x) mi_calloc(x, 1) #define vm_realloc(x, y) mi_realloc(x, y) #define vm_free(x) mi_free((void *) (x)) #define vm_strdup(x) mi_strdup(x) +#endif + +#if VM_MALLOC_SYS +#define vm_malloc(x) malloc(x) +#define vm_calloc(x) calloc(x, 1) +#define vm_realloc(x, y) realloc(x, y) +#define vm_free(x) free((void *) (x)) +#define vm_strdup(x) strdup(x) +#endif #endif diff --git a/vm/lua/repl.c b/vm/lua/repl.c index d3956a8d..0754061b 100644 --- a/vm/lua/repl.c +++ b/vm/lua/repl.c @@ -7,7 +7,6 @@ #include "../ast/ast.h" #include "../ast/comp.h" #include "../backend/backend.h" -#include "../primes.inc" #include "../../vendor/tree-sitter/lib/include/tree_sitter/api.h" @@ -33,9 +32,9 @@ void vm_lang_lua_repl_completer(ic_completion_env_t *cenv, const char *prefix) { with_new_std:; uint64_t len = vm_primes_table[std->size]; for (size_t i = 0; i < len; i++) { - vm_table_pair_t *pair = &std->pairs[i]; - if (vm_obj_is_table(pair->key)) { - const char *got = vm_obj_get_string(pair->key)->buf; + vm_obj_t std_key = std->entries[i]; + if (vm_obj_is_table(std_key)) { + const char *got = vm_obj_get_string(std_key)->buf; size_t i = 0; while (got[i] != '\0') { if (last_word[i] == '\0') { @@ -53,9 +52,9 @@ with_new_std:; continue; } } - if (vm_obj_is_nil(pair->value)) { + if (vm_obj_is_nil(std_key)) { if (last_word[i] == '.') { - std = vm_obj_get_table(pair->key); + std = vm_obj_get_table(std_key); last_word = &last_word[i + 1]; goto with_new_std; } diff --git a/vm/obj.c b/vm/obj.c index ff6bdd6c..cf3b846a 100644 --- a/vm/obj.c +++ b/vm/obj.c @@ -3,8 +3,6 @@ #include "io.h" #include "math.h" -#include "primes.inc" - vm_obj_t vm_obj_of_string(vm_t *vm, const char *str) { vm_obj_t ret = vm_obj_of_buffer(vm_io_buffer_from_str(str)); vm_gc_add(vm, ret); @@ -50,52 +48,49 @@ uint32_t vm_obj_hash(vm_obj_t value) { return 0; } -static vm_table_pair_t *vm_table_lookup(vm_obj_table_t *table, vm_obj_t key) { +vm_obj_t vm_table_get(vm_obj_table_t *table, vm_obj_t key) { size_t len = vm_primes_table[table->size]; size_t init_look = vm_primes_mod(table->size, vm_obj_hash(key)); size_t look = init_look; do { - vm_table_pair_t *pair = &table->pairs[look]; - if (vm_obj_is_nil(pair->key)) { - return NULL; + vm_obj_t found_key = table->entries[look]; + if (vm_obj_is_nil(found_key)) { + return vm_obj_of_nil(); } - if (vm_obj_unsafe_eq(key, pair->key)) { - return pair; + if (vm_obj_unsafe_eq(key, found_key)) { + return table->entries[vm_primes_table[table->size] + look]; } look += 1; if (look == len) { look = 0; } } while (look != init_look); - return NULL; + + return vm_obj_of_nil(); } void vm_table_set(vm_obj_table_t *restrict table, vm_obj_t key, vm_obj_t value) { size_t len = vm_primes_table[table->size]; size_t look = vm_primes_mod(table->size, vm_obj_hash(key)); for (size_t i = 0; i < len; i++) { - vm_table_pair_t *pair = &table->pairs[look]; - if (vm_obj_is_nil(pair->key)) { + vm_obj_t table_key = table->entries[look]; + if (vm_obj_is_nil(table_key)) { break; } - if (vm_obj_unsafe_eq(key, pair->key)) { - if (vm_obj_is_nil(key)) { - pair->key = vm_obj_of_nil(); + if (vm_obj_unsafe_eq(key, table_key)) { + if (vm_obj_is_nil(value)) { if (vm_obj_is_number(key)) { double f64val = vm_obj_get_number(key); - if ((double)INT64_MIN <= f64val && f64val <= (double)INT64_MAX) { - int64_t i64val = (int64_t)f64val; + if (1 <= f64val && f64val <= table->len) { + int32_t i64val = (int32_t)f64val; if ((double)i64val == f64val) { - if (0 < i64val && i64val <= table->len) { - table->len = i64val - 1; - } + table->len = i64val - 1; } } } - } else { - pair->key = key; - pair->value = value; + table->entries[look] = value; } + table->entries[vm_primes_table[table->size] + look] = value; return; } look += 1; @@ -103,67 +98,41 @@ void vm_table_set(vm_obj_table_t *restrict table, vm_obj_t key, vm_obj_t value) look = 0; } } - if (vm_obj_is_nil(value)) { - table->pairs[look] = (vm_table_pair_t){ - .key = vm_obj_of_nil(), - .value = value, - }; - - if (vm_obj_is_number(value)) { - double n = vm_obj_get_number(value); - - if (1 <= n && n <= table->len && (double)(size_t)n == n) { - table->len = (size_t)(n - 1); - } - } - } else if (vm_primes_table[table->size] <= 4 ? table->used == vm_primes_table[table->size] : (table->used) * 100u > vm_primes_table[table->size] * 75u) { + if ((table->used) * 100u > vm_primes_table[table->size] * 75u) { vm_obj_table_t ret; ret.size = table->size + 1; - uint64_t ret_len = vm_primes_table[ret.size]; -#if VM_EMPTY_BYTE == 0 - ret.pairs = vm_calloc(sizeof(vm_table_pair_t) * ret_len); -#else - ret.pairs = vm_malloc(sizeof(vm_table_pair_t) * ret_len); - memset(ret.pairs, VM_EMPTY_BYTE, sizeof(vm_table_pair_t) * ret_len); -#endif ret.used = 0; ret.len = 0; ret.mark = table->mark; - size_t table_len = vm_primes_table[table->size]; - for (size_t i = 0; i < table_len; i++) { - vm_table_pair_t *in_pair = &table->pairs[i]; - vm_obj_t in_key = in_pair->key; - if (!vm_obj_is_nil(key)) { - vm_table_set(&ret, in_key, in_pair->value); +#if VM_EMPTY_BYTE == 0 + ret.entries = vm_calloc(sizeof(vm_obj_t) * vm_primes_table[ret.size] * 2); +#else + ret.entries = vm_malloc(sizeof(vm_obj_t) * vm_primes_table[ret.size] * 2); + memset(ret.entries, VM_EMPTY_BYTE, sizeof(vm_obj_t) * vm_primes_table[ret.size] * 2); +#endif + for (size_t i = 0; i < vm_primes_table[table->size]; i++) { + vm_obj_t in_key = table->entries[i]; + if (!vm_obj_is_nil(in_key)) { + vm_table_set(&ret, in_key, table->entries[vm_primes_table[table->size] + i]); } } vm_table_set(&ret, key, value); - vm_free(table->pairs); + vm_free(table->entries); *table = ret; } else { table->used += 1; - table->pairs[look] = (vm_table_pair_t){ - .key = key, - .value = value, - }; - vm_obj_t vlen = vm_obj_of_number(table->len + 1); - if (vm_obj_unsafe_eq(vlen, key)) { + table->entries[look] = key; + table->entries[vm_primes_table[table->size] + look] = value; + int32_t next = table->len + 1; + if (vm_obj_is_number(key) && vm_obj_get_number(key) == next) { while (true) { - int32_t next = table->len + 1; - vm_table_pair_t *got = vm_table_lookup(table, vm_obj_of_number(next)); - if (got == NULL) { + vm_obj_t got = vm_table_get(table, vm_obj_of_number(next + 1)); + if (vm_obj_is_nil(got)) { break; } - table->len = next; + next += 1; } + table->len = next; } } } - -vm_obj_t vm_table_get(vm_obj_table_t *table, vm_obj_t key) { - vm_table_pair_t *pair = vm_table_lookup(table, key); - if (pair == NULL) { - return vm_obj_of_nil(); - } - return pair->value; -} diff --git a/vm/obj.h b/vm/obj.h index 205ca291..baf2782c 100644 --- a/vm/obj.h +++ b/vm/obj.h @@ -3,9 +3,6 @@ #include "lib.h" -struct vm_table_pair_t; -typedef struct vm_table_pair_t vm_table_pair_t; - vm_obj_t vm_obj_of_string(vm_t *vm, const char *str); uint32_t vm_obj_hash(vm_obj_t value); diff --git a/vm/std.c b/vm/std.c index 1ffe4eaf..34abe2e6 100644 --- a/vm/std.c +++ b/vm/std.c @@ -8,8 +8,6 @@ #include "gc.h" #include "io.h" -#include "primes.inc" - void vm_std_os_exit(vm_t *vm, size_t nargs, vm_obj_t *args) { (void)vm; exit((int)vm_obj_get_number(args[0])); @@ -104,22 +102,14 @@ void vm_std_vm_print(vm_t *vm, size_t nargs, vm_obj_t *args) { void vm_std_vm_concat(vm_t *vm, size_t nargs, vm_obj_t *args) { (void)vm; - size_t len = 1; + vm_io_buffer_t *buf = vm_io_buffer_new(); for (size_t i = 0; i < nargs; i++) { - len += vm_obj_get_string(args[i])->len; - } - char *buf = vm_malloc(sizeof(char) * len); - size_t head = 0; - for (size_t i = 0; vm_obj_is_string(args[i]); i++) { - size_t len = vm_obj_get_string(args[i])->len; - if (len == 0) { - continue; - } - memcpy(&buf[head], vm_obj_get_string(args[i])->buf, len); - head += len; + vm_io_buffer_object_tostring(buf, args[i]); } - buf[len - 1] = '\0'; - *args = vm_obj_of_string(vm, buf); + vm_obj_t ret = vm_obj_of_buffer(buf); + vm_gc_add(vm, ret); + *args = ret; + return; } void vm_std_math_rand_int(vm_t *vm, size_t nargs, vm_obj_t *args) { @@ -152,7 +142,7 @@ void vm_std_tostring(vm_t *vm, size_t nargs, vm_obj_t *args) { vm_io_buffer_t *buf = vm_io_buffer_new(); vm_io_buffer_object_tostring(buf, *args); vm_obj_t ret = vm_obj_of_buffer(buf); - vm_gc_add(vm->gc, ret); + vm_gc_add(vm, ret); *args = ret; return; } @@ -202,15 +192,48 @@ void vm_std_io_write(vm_t *vm, size_t nargs, vm_obj_t *args) { return; } +void vm_std_string_sub(vm_t *vm, size_t nargs, vm_obj_t *args) { + if (nargs == 0 || !vm_obj_is_string(args[0])) { + args[0] = vm_obj_of_error(vm_error_from_msg(VM_LOCATION_RANGE_FUNC, "string.sub: first argument not a string")); + return; + } + vm_io_buffer_t *buf = vm_obj_get_string(args[0]); + if (nargs == 1 || !vm_obj_is_number(args[1])) { + args[0] = vm_obj_of_error(vm_error_from_msg(VM_LOCATION_RANGE_FUNC, "string.sub: second argument not a number")); + return; + } + int32_t start = (int32_t) vm_obj_get_number(args[1]); + if (nargs == 2) { + vm_io_buffer_t *out = vm_io_buffer_new(); + for (int32_t i = start-1; i <= out->len-1; i++) { + vm_io_buffer_format(out, "%c", (int) buf->buf[i]); + } + vm_gc_add(vm, args[0] = vm_obj_of_buffer(out)); + return; + } else { + if (!vm_obj_is_number(args[2])) { + args[0] = vm_obj_of_error(vm_error_from_msg(VM_LOCATION_RANGE_FUNC, "string.sub: third argument not a number")); + return; + } + int32_t stop = (int32_t) vm_obj_get_number(args[2]); + vm_io_buffer_t *out = vm_io_buffer_new(); + for (int32_t i = start-1; i <= stop-1; i++) { + vm_io_buffer_format(out, "%c", (int) buf->buf[i]); + } + vm_gc_add(vm, args[0] = vm_obj_of_buffer(out)); + return; + } +} + void vm_std_string_format(vm_t *vm, size_t nargs, vm_obj_t *args) { (void)vm; - vm_io_buffer_t *out = vm_io_buffer_new(); size_t argnum = 0; vm_obj_t fmt = args[argnum++]; if (!vm_obj_is_string(fmt)) { args[0] = vm_obj_of_error(vm_error_from_msg(VM_LOCATION_RANGE_FUNC, "invalid format (not a string)")); return; } + vm_io_buffer_t *out = vm_io_buffer_new(); const char *str = vm_obj_get_string(fmt)->buf; while (*str != '\0') { const char *head = str; @@ -362,9 +385,7 @@ void vm_std_string_format(vm_t *vm, size_t nargs, vm_obj_t *args) { } } } - args[0] = vm_obj_of_string(vm, out->buf); - vm_free(out->buf); - vm_free(out); + vm_gc_add(vm, args[0] = vm_obj_of_buffer(out)); } void vm_std_set_arg(vm_t *vm, const char *prog, const char *file, int argc, char **argv) { @@ -392,10 +413,10 @@ void vm_std_table_keys(vm_t *vm, size_t nargs, vm_obj_t *args) { size_t len = vm_primes_table[tab->size]; size_t write_head = 1; for (size_t i = 0; i < len; i++) { - vm_table_pair_t *pair = &tab->pairs[i]; - if (!vm_obj_is_nil(pair->key)) { - vm_obj_t key = vm_obj_of_number(write_head); - vm_table_set(ret, key, pair->key); + vm_obj_t key = tab->entries[i]; + if (!vm_obj_is_nil(key)) { + vm_obj_t nth = vm_obj_of_number(write_head); + vm_table_set(ret, nth, key); write_head++; } } @@ -413,10 +434,9 @@ void vm_std_table_values(vm_t *vm, size_t nargs, vm_obj_t *args) { size_t len = vm_primes_table[tab->size]; size_t write_head = 1; for (size_t i = 0; i < len; i++) { - vm_table_pair_t *pair = &tab->pairs[i]; - if (!vm_obj_is_nil(pair->key)) { - vm_obj_t key = vm_obj_of_number(write_head); - vm_table_set(ret, key, pair->value); + if (!vm_obj_is_nil(tab->entries[i])) { + vm_obj_t nth = vm_obj_of_number(write_head); + vm_table_set(ret, nth, tab->entries[vm_primes_table[tab->size] + i]); write_head++; } } @@ -440,70 +460,10 @@ void vm_std_vm_import(vm_t *vm, size_t nargs, vm_obj_t *args) { return; } -// void vm_std_lang_eb_if(vm_t *vm, size_t nargs, vm_obj_t *args) { -// if (!vm_obj_is_number(args[0])) { -// args[0] = vm_obj_of_error(vm_error_from_msg(VM_LOCATION_RANGE_UNKNOWN, "pass if a number")); -// return; -// } -// vm_obj_t obj; -// if (vm_obj_get_number(args[0]) != 0) { -// obj = args[1]; -// } else { -// obj = args[2]; -// } -// if (!vm_obj_is_closure(obj)) { -// args[0] = vm_obj_of_error(vm_error_from_msg(VM_LOCATION_RANGE_UNKNOWN, "define if like: (if c (t) (f)) ?")); -// return; -// } -// vm_obj_closure_t *closure = vm_obj_get_closure(obj); -// for (size_t i = 0; i < closure->len; i++) { -// vm->regs[i] = closure->values[i]; -// } -// vm_obj_t ret = vm_run_repl(vm, closure->block); -// args[0] = ret; -// return; -// } - -void vm_std_lang_eb_error(vm_t *vm, size_t nargs, vm_obj_t *args) { - if (nargs == 0) { - args[0] = vm_obj_of_error(vm_error_from_msg(VM_LOCATION_RANGE_UNKNOWN, "error")); - return; - } - vm_io_buffer_t *buf = vm_io_buffer_new(); - vm_io_buffer_obj_debug(buf, 0, "error: ", args[0], NULL); - args[0] = vm_obj_of_error(vm_error_from_msg(VM_LOCATION_RANGE_UNKNOWN, "")); - free(buf->buf); - free(buf); - return; -} - -void vm_std_lang_eb_putchar(vm_t *vm, size_t nargs, vm_obj_t *args) { - if (nargs == 0 || !vm_obj_is_number(args[0])) { - args[0] = vm_obj_of_error(vm_error_from_msg(VM_LOCATION_RANGE_UNKNOWN, "putchar: takes a number")); - return; - } - printf("%c", (int) vm_obj_get_number(args[0])); - args[0] = vm_obj_of_nil(); - return; -} - void vm_std_new(vm_t *vm) { vm_obj_table_t *std = vm_table_new(vm); srand(0); - - { - vm_obj_table_t *lang = vm_table_new(vm); - vm_table_set(std, vm_obj_of_string(vm, "lang"), vm_obj_of_table(lang)); - - { - vm_obj_table_t *eb = vm_table_new(vm); - vm_table_set(lang, vm_obj_of_string(vm, "eb"), vm_obj_of_table(eb)); - vm_table_set(eb, vm_obj_of_string(vm, "putchar"), vm_obj_of_ffi(vm_std_lang_eb_putchar)); - vm_table_set(eb, vm_obj_of_string(vm, "error"), vm_obj_of_ffi(vm_std_lang_eb_error)); - vm_table_set(eb, vm_obj_of_string(vm, "debug"), vm_obj_of_ffi(vm_std_vm_print)); - } - } { vm_obj_table_t *io = vm_table_new(vm); @@ -515,6 +475,7 @@ void vm_std_new(vm_t *vm) { vm_obj_table_t *string = vm_table_new(vm); vm_table_set(std, vm_obj_of_string(vm, "string"), vm_obj_of_table(string)); vm_table_set(string, vm_obj_of_string(vm, "format"), vm_obj_of_ffi(vm_std_string_format)); + vm_table_set(string, vm_obj_of_string(vm, "sub"), vm_obj_of_ffi(vm_std_string_sub)); } { @@ -524,7 +485,7 @@ void vm_std_new(vm_t *vm) { vm_table_set(tvm, vm_obj_of_string(vm, "gc"), vm_obj_of_ffi(vm_std_vm_gc)); vm_table_set(tvm, vm_obj_of_string(vm, "print"), vm_obj_of_ffi(vm_std_vm_print)); vm_table_set(tvm, vm_obj_of_string(vm, "version"), vm_obj_of_string(vm, VM_VERSION)); - vm_table_set(tvm, vm_obj_of_string(vm, "conacat"), vm_obj_of_ffi(vm_std_vm_concat)); + vm_table_set(tvm, vm_obj_of_string(vm, "concat"), vm_obj_of_ffi(vm_std_vm_concat)); } { diff --git a/vm/vm.h b/vm/vm.h index 2f3ea9e2..0f57e154 100644 --- a/vm/vm.h +++ b/vm/vm.h @@ -9,9 +9,14 @@ #define VM_VERSION "0.0.5" -#define VM_GC_MIN 16 -#define VM_GC_FACTOR 1.7 +#define VM_MALLOC_MI 0 +#define VM_MALLOC_SYS 1 + +#define VM_GC_MIN 256 +#define VM_GC_FACTOR 1.4 #define VM_GC_STATS 0 +#define VM_GC_STATS_DEBUG 0 +#define VM_GC_DISABLED 1 #define VM_DEBUG_BACKEND_BLOCKS 0 #define VM_DEBUG_BACKEND_OPCODES 0 @@ -30,8 +35,6 @@ struct vm_ir_blocks_t; struct vm_obj_closure_t; struct vm_obj_gc_header_t; struct vm_obj_table_t; -struct vm_table_pair_t; -struct vm_table_pair_t; struct vm_io_buffer_t; typedef struct vm_io_buffer_t vm_io_buffer_t; @@ -41,18 +44,12 @@ typedef struct vm_ir_block_t vm_ir_block_t; typedef struct vm_ir_blocks_t vm_ir_blocks_t; typedef struct vm_obj_closure_t vm_obj_closure_t; typedef struct vm_obj_table_t vm_obj_table_t; -typedef struct vm_table_pair_t vm_table_pair_t; typedef nanbox_t vm_obj_t; typedef void vm_ffi_t(vm_t *vm, size_t nargs, vm_obj_t *args); -struct vm_table_pair_t { - vm_obj_t key; - vm_obj_t value; -}; - struct vm_obj_table_t { - vm_table_pair_t *restrict pairs; + vm_obj_t *restrict entries; uint32_t used: 28; uint32_t len: 28; uint8_t size: 5; @@ -91,5 +88,6 @@ vm_t *vm_state_new(void); void vm_state_delete(vm_t *vm); #include "obj.inc" +#include "primes.inc" #endif