mirror of
https://github.com/centau/vide.git
synced 2026-08-20 14:41:37 +00:00
Try improve error reporting
This commit is contained in:
parent
3b22f6ccf9
commit
58a31a1b32
16 changed files with 164 additions and 55 deletions
|
|
@ -23,6 +23,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
for this.
|
for this.
|
||||||
- Implicit effects to set children now unparent all children when the effect is
|
- Implicit effects to set children now unparent all children when the effect is
|
||||||
destroyed.
|
destroyed.
|
||||||
|
- Error reporting should be improved with better formatting when effects invoke
|
||||||
|
other effects and no more loss of stack traces.
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
local typeof = game and typeof or require "../test/mock".typeof :: never
|
local typeof = game and typeof or require "../test/mock".typeof :: never
|
||||||
|
|
||||||
local flags = require "./flags"
|
local flags = require "./flags"
|
||||||
local throw = require "./throw"
|
|
||||||
local implicit_effect = require "./implicit_effect"
|
local implicit_effect = require "./implicit_effect"
|
||||||
local _, is_action = require "./action"()
|
local _, is_action = require "./action"()
|
||||||
local graph = require "./graph"
|
local graph = require "./graph"
|
||||||
|
|
@ -67,7 +66,7 @@ local function process_properties(properties: Map<unknown, unknown>, instance: I
|
||||||
if type(property) == "string" then
|
if type(property) == "string" then
|
||||||
if flags.strict then -- check for duplicate property assignment at nesting depth
|
if flags.strict then -- check for duplicate property assignment at nesting depth
|
||||||
if cache.nested_debug[depth][property] then
|
if cache.nested_debug[depth][property] then
|
||||||
throw(`duplicate property {property} at depth {depth}`)
|
error(`duplicate property {property} at depth {depth}`, 0)
|
||||||
end
|
end
|
||||||
cache.nested_debug[depth][property] = true
|
cache.nested_debug[depth][property] = true
|
||||||
end
|
end
|
||||||
|
|
@ -104,7 +103,7 @@ end
|
||||||
-- applies table of nested properties to an instance using full vide semantics
|
-- applies table of nested properties to an instance using full vide semantics
|
||||||
local function apply<T>(instance: T & Instance, properties: { [unknown]: unknown }): T
|
local function apply<T>(instance: T & Instance, properties: { [unknown]: unknown }): T
|
||||||
if not properties then
|
if not properties then
|
||||||
throw("attempt to call a constructor returned by create() with no properties")
|
error "attempt to call a constructor returned by create() with no properties"
|
||||||
end
|
end
|
||||||
|
|
||||||
-- queue parent assignment if any for last
|
-- queue parent assignment if any for last
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
local flags = require "./flags"
|
local flags = require "./flags"
|
||||||
local throw = require "./throw"
|
|
||||||
local graph = require "./graph"
|
local graph = require "./graph"
|
||||||
|
|
||||||
local function batch(setter: () -> ())
|
local function batch(setter: () -> ())
|
||||||
|
|
@ -11,14 +10,14 @@ local function batch(setter: () -> ())
|
||||||
from = graph.get_update_queue_length()
|
from = graph.get_update_queue_length()
|
||||||
end
|
end
|
||||||
|
|
||||||
local ok, err: string? = pcall(setter)
|
local ok, err: string? = xpcall(setter, debug.traceback)
|
||||||
|
|
||||||
if not already_batching then
|
if not already_batching then
|
||||||
flags.batch = false
|
flags.batch = false
|
||||||
graph.flush_update_queue(from)
|
graph.flush_update_queue(from)
|
||||||
end
|
end
|
||||||
|
|
||||||
if not ok then throw(`error occured while batching updates: {err}`) end
|
if not ok then error(`error occured while batching updates: {err}`, 0) end
|
||||||
end
|
end
|
||||||
|
|
||||||
return batch
|
return batch
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
local typeof = game and typeof or require "../test/mock".typeof :: never
|
local typeof = game and typeof or require "../test/mock".typeof :: never
|
||||||
|
|
||||||
local throw = require "./throw"
|
|
||||||
local graph = require "./graph"
|
local graph = require "./graph"
|
||||||
local get_scope = graph.get_scope
|
local get_scope = graph.get_scope
|
||||||
local push_cleanup = graph.push_cleanup
|
local push_cleanup = graph.push_cleanup
|
||||||
|
|
@ -14,14 +13,14 @@ local function helper(obj: any)
|
||||||
elseif obj.disconnect then function() obj:disconnect() end
|
elseif obj.disconnect then function() obj:disconnect() end
|
||||||
elseif obj.Destroy then function() obj:Destroy() end
|
elseif obj.Destroy then function() obj:Destroy() end
|
||||||
elseif obj.Disconnect then function() obj:Disconnect() end
|
elseif obj.Disconnect then function() obj:Disconnect() end
|
||||||
else throw("cannot cleanup given object")
|
else error "cannot cleanup given object"
|
||||||
end
|
end
|
||||||
|
|
||||||
local function cleanup(value: unknown)
|
local function cleanup(value: unknown)
|
||||||
local scope = get_scope()
|
local scope = get_scope()
|
||||||
|
|
||||||
if not scope then
|
if not scope then
|
||||||
throw "cannot cleanup outside a stable or reactive scope"
|
error "cannot cleanup outside a stable or reactive scope"
|
||||||
end; assert(scope)
|
end; assert(scope)
|
||||||
|
|
||||||
if type(value) == "function" then
|
if type(value) == "function" then
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
local throw = require "./throw"
|
|
||||||
local graph = require "./graph"
|
local graph = require "./graph"
|
||||||
type Node<T> = graph.Node<T>
|
type Node<T> = graph.Node<T>
|
||||||
local create_node = graph.create_node
|
local create_node = graph.create_node
|
||||||
|
|
@ -44,10 +43,10 @@ local function context<T>(...: T): Context<T>
|
||||||
if has_default ~= nil then
|
if has_default ~= nil then
|
||||||
return default_value
|
return default_value
|
||||||
else
|
else
|
||||||
throw("attempt to get context when no context is set and no default context is set")
|
error("attempt to get context when no context is set and no default context is set", 0)
|
||||||
end
|
end
|
||||||
else -- set
|
else -- set
|
||||||
if not scope then return throw("attempt to set context outside of a vide scope") end
|
if not scope then return error("attempt to set context outside of a vide scope", 0) end
|
||||||
|
|
||||||
local value, component = ...
|
local value, component = ...
|
||||||
|
|
||||||
|
|
@ -62,7 +61,7 @@ local function context<T>(...: T): Context<T>
|
||||||
pop_scope()
|
pop_scope()
|
||||||
|
|
||||||
if not ok then
|
if not ok then
|
||||||
throw(`error while running context:\n\n{result}`)
|
error(`error while running context:\n\n{result}`, 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
local typeof = game and typeof or require "../test/mock".typeof :: never
|
local typeof = game and typeof or require "../test/mock".typeof :: never
|
||||||
local Instance = game and Instance or require "../test/mock".Instance :: never
|
local Instance = game and Instance or require "../test/mock".Instance :: never
|
||||||
|
|
||||||
local throw = require "./throw"
|
|
||||||
local defaults = require "./defaults"
|
local defaults = require "./defaults"
|
||||||
local apply = require "./apply"
|
local apply = require "./apply"
|
||||||
|
|
||||||
|
|
@ -10,7 +9,7 @@ local ctor_cache = {} :: { [string]: () -> Instance }
|
||||||
setmetatable(ctor_cache :: any, {
|
setmetatable(ctor_cache :: any, {
|
||||||
__index = function(self, class)
|
__index = function(self, class)
|
||||||
local ok, instance: Instance = pcall(Instance.new, class :: any)
|
local ok, instance: Instance = pcall(Instance.new, class :: any)
|
||||||
if not ok then throw(`invalid class name, could not create instance of class { class }`) end
|
if not ok then error(`invalid class name, could not create instance of class { class }`, 0) end
|
||||||
|
|
||||||
local default: { [string]: unknown }? = defaults[class]
|
local default: { [string]: unknown }? = defaults[class]
|
||||||
if default then
|
if default then
|
||||||
|
|
@ -35,7 +34,7 @@ end
|
||||||
local function clone_instance(instance: Instance)
|
local function clone_instance(instance: Instance)
|
||||||
return function(properties: Props): Instance
|
return function(properties: Props): Instance
|
||||||
local clone = instance:Clone()
|
local clone = instance:Clone()
|
||||||
if not clone then throw "attempt to clone a non-archivable instance" end
|
if not clone then error "attempt to clone a non-archivable instance" end
|
||||||
return apply(clone, properties)
|
return apply(clone, properties)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -47,7 +46,7 @@ local function create(class_or_instance: string | Instance, props: Props?): ((Pr
|
||||||
elseif typeof(class_or_instance) == "Instance" then
|
elseif typeof(class_or_instance) == "Instance" then
|
||||||
result = clone_instance(class_or_instance)
|
result = clone_instance(class_or_instance)
|
||||||
else
|
else
|
||||||
throw("bad argument #1, expected string or instance, got " .. typeof(class_or_instance))
|
error("bad argument #1, expected string or instance, got " .. typeof(class_or_instance), 0)
|
||||||
return nil :: never
|
return nil :: never
|
||||||
end
|
end
|
||||||
if props then
|
if props then
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
local throw = require "./throw"
|
|
||||||
local flags = require "./flags"
|
local flags = require "./flags"
|
||||||
|
|
||||||
export type SourceNode<T> = {
|
export type SourceNode<T> = {
|
||||||
|
|
@ -22,9 +21,23 @@ export type Node<T> = {
|
||||||
|
|
||||||
local scopes = { n = 0 } :: { [number]: Node<any>, n: number } -- scopes stack
|
local scopes = { n = 0 } :: { [number]: Node<any>, n: number } -- scopes stack
|
||||||
|
|
||||||
|
local function efn(err: string)
|
||||||
|
local trace = debug.traceback(err, 2)
|
||||||
|
|
||||||
|
if string.find(err, "^effect error stacktrace") then -- if effect error is nested
|
||||||
|
trace = string.gsub(" " .. trace, "\n", function() -- indent entire error
|
||||||
|
return "\n "
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
trace ..= "\nsource update stacktrace:"
|
||||||
|
return trace
|
||||||
|
end
|
||||||
|
|
||||||
local function ycall<T, U>(fn: (T) -> U, arg: T): (boolean, string|U)
|
local function ycall<T, U>(fn: (T) -> U, arg: T): (boolean, string|U)
|
||||||
|
|
||||||
local thread = coroutine.create(xpcall)
|
local thread = coroutine.create(xpcall)
|
||||||
local function efn(err: string) return debug.traceback(err, 3) end
|
--local function efn(err: string) return debug.traceback(err, 3) end
|
||||||
local resume_ok, run_ok, result = coroutine.resume(thread, fn, efn, arg)
|
local resume_ok, run_ok, result = coroutine.resume(thread, fn, efn, arg)
|
||||||
|
|
||||||
assert(resume_ok)
|
assert(resume_ok)
|
||||||
|
|
@ -45,9 +58,9 @@ local function assert_stable_scope(): Node<unknown>
|
||||||
|
|
||||||
if not scope then
|
if not scope then
|
||||||
local caller_name = debug.info(2, "n")
|
local caller_name = debug.info(2, "n")
|
||||||
return throw(`cannot use {caller_name}() outside a stable or reactive scope`)
|
return error(`cannot use {caller_name}() outside a stable or reactive scope`, 0)
|
||||||
elseif scope.effect then
|
elseif scope.effect then
|
||||||
throw("cannot create a new reactive scope inside another reactive scope")
|
error("cannot create a new reactive scope inside another reactive scope", 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
return scope
|
return scope
|
||||||
|
|
@ -81,8 +94,8 @@ end
|
||||||
local function flush_cleanups<T>(node: Node<T>)
|
local function flush_cleanups<T>(node: Node<T>)
|
||||||
if node.cleanups then
|
if node.cleanups then
|
||||||
for _, fn in next, node.cleanups do
|
for _, fn in next, node.cleanups do
|
||||||
local ok, err: string? = pcall(fn)
|
local ok, err: string? = xpcall(fn, debug.traceback)
|
||||||
if not ok then throw(`cleanup error: {err}`) end
|
if not ok then error(`cleanup error: {err}`, 0) end
|
||||||
end
|
end
|
||||||
|
|
||||||
table.clear(node.cleanups)
|
table.clear(node.cleanups)
|
||||||
|
|
@ -107,7 +120,7 @@ end
|
||||||
|
|
||||||
local function destroy<T>(node: Node<T>)
|
local function destroy<T>(node: Node<T>)
|
||||||
if flags.strict and table.find(scopes, node) then
|
if flags.strict and table.find(scopes, node) then
|
||||||
throw("attempt to destroy an active scope")
|
error("attempt to destroy an active scope", 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
flush_cleanups(node)
|
flush_cleanups(node)
|
||||||
|
|
@ -150,7 +163,7 @@ local function evaluate_node<T>(node: Node<T>)
|
||||||
if not ok then
|
if not ok then
|
||||||
table.clear(update_queue)
|
table.clear(update_queue)
|
||||||
update_queue.n = 0
|
update_queue.n = 0
|
||||||
throw(`effect stacktrace:\n{new_value :: string}`)
|
error(`effect error stacktrace\n{new_value :: string}`, 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
node.cache = new_value :: T
|
node.cache = new_value :: T
|
||||||
|
|
@ -170,7 +183,7 @@ local function evaluate_node<T>(node: Node<T>)
|
||||||
if not ok then
|
if not ok then
|
||||||
table.clear(update_queue)
|
table.clear(update_queue)
|
||||||
update_queue.n = 0
|
update_queue.n = 0
|
||||||
throw(`effect stacktrace:\n{new_value}\n`)
|
error(`effect error:\n{new_value}\n`, 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
node.cache = new_value
|
node.cache = new_value
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ local indexes, values = require "./maps"()
|
||||||
local spring, update_springs = require "./spring"()
|
local spring, update_springs = require "./spring"()
|
||||||
local action = require "./action"()
|
local action = require "./action"()
|
||||||
local changed = require "./changed"
|
local changed = require "./changed"
|
||||||
local throw = require "./throw"
|
|
||||||
local flags = require "./flags"
|
local flags = require "./flags"
|
||||||
|
|
||||||
export type Source<T> = source.Source<T>
|
export type Source<T> = source.Source<T>
|
||||||
|
|
@ -98,7 +97,7 @@ local vide = {
|
||||||
setmetatable(vide :: any, {
|
setmetatable(vide :: any, {
|
||||||
__index = function(_, index: unknown): ()
|
__index = function(_, index: unknown): ()
|
||||||
if flags[index] == nil then
|
if flags[index] == nil then
|
||||||
throw(`{tostring(index)} is not a valid member of vide`)
|
error(`{tostring(index)} is not a valid member of vide`, 0)
|
||||||
else
|
else
|
||||||
return flags[index]
|
return flags[index]
|
||||||
end
|
end
|
||||||
|
|
@ -106,7 +105,7 @@ setmetatable(vide :: any, {
|
||||||
|
|
||||||
__newindex = function(_, index: unknown, value: unknown)
|
__newindex = function(_, index: unknown, value: unknown)
|
||||||
if flags[index] == nil then
|
if flags[index] == nil then
|
||||||
throw(`{tostring(index)} is not a valid member of vide`)
|
error(`{tostring(index)} is not a valid member of vide, 0`)
|
||||||
else
|
else
|
||||||
flags[index] = value
|
flags[index] = value
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
local throw = require "./throw"
|
|
||||||
local flags = require "./flags"
|
local flags = require "./flags"
|
||||||
local graph = require "./graph"
|
local graph = require "./graph"
|
||||||
type Node<T> = graph.Node<T>
|
type Node<T> = graph.Node<T>
|
||||||
|
|
@ -20,7 +19,7 @@ local function check_primitives(t: {})
|
||||||
|
|
||||||
for _, v in next, t do
|
for _, v in next, t do
|
||||||
if type(v) == "table" or type(v) == "userdata" or type(v) == "function" then continue end
|
if type(v) == "table" or type(v) == "userdata" or type(v) == "function" then continue end
|
||||||
throw("table source map cannot return primitives")
|
error("table source map cannot return primitives", 0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -71,7 +70,7 @@ local function indexes<K, VI, VO>(input: () -> Map<K, VI>, transform: (() -> VI,
|
||||||
|
|
||||||
push_scope(scope)
|
push_scope(scope)
|
||||||
|
|
||||||
local ok, result = pcall(transform, function()
|
local ok, result = xpcall(transform, debug.traceback, function()
|
||||||
push_child_to_scope(node)
|
push_child_to_scope(node)
|
||||||
return node.cache
|
return node.cache
|
||||||
end, i)
|
end, i)
|
||||||
|
|
@ -132,7 +131,7 @@ local function values<K, VI, VO>(input: () -> Map<K, VI>, transform: (VI, () ->
|
||||||
local cache = {}
|
local cache = {}
|
||||||
for _, v in next, data do
|
for _, v in next, data do
|
||||||
if cache[v] ~= nil then
|
if cache[v] ~= nil then
|
||||||
throw "duplicate table value detected"
|
error "duplicate table value detected"
|
||||||
end
|
end
|
||||||
cache[v] = true
|
cache[v] = true
|
||||||
end
|
end
|
||||||
|
|
@ -154,7 +153,7 @@ local function values<K, VI, VO>(input: () -> Map<K, VI>, transform: (VI, () ->
|
||||||
|
|
||||||
push_scope(scope)
|
push_scope(scope)
|
||||||
|
|
||||||
local ok, result = pcall(transform, v, function()
|
local ok, result = xpcall(transform, debug.traceback, v, function()
|
||||||
push_child_to_scope(node)
|
push_child_to_scope(node)
|
||||||
return node.cache
|
return node.cache
|
||||||
end)
|
end)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
local throw = require "./throw"
|
|
||||||
local graph = require "./graph"
|
local graph = require "./graph"
|
||||||
type Node<T> = graph.Node<T>
|
type Node<T> = graph.Node<T>
|
||||||
local create_node = graph.create_node
|
local create_node = graph.create_node
|
||||||
|
|
@ -14,21 +13,20 @@ local function root<T...>(fn: (destroy: () -> ()) -> T...): (() -> (), T...)
|
||||||
refs[node] = true -- prevent gc of root node
|
refs[node] = true -- prevent gc of root node
|
||||||
|
|
||||||
local destroy = function()
|
local destroy = function()
|
||||||
if not refs[node] then throw "root already destroyed" end
|
if not refs[node] then error "root already destroyed" end
|
||||||
refs[node] = nil
|
refs[node] = nil
|
||||||
destroy(node)
|
destroy(node)
|
||||||
end
|
end
|
||||||
|
|
||||||
push_scope(node)
|
push_scope(node)
|
||||||
|
|
||||||
local function efn(err: string) return debug.traceback(err, 3) end
|
local result = { xpcall(fn, debug.traceback, destroy) }
|
||||||
local result = { xpcall(fn, efn, destroy) }
|
|
||||||
|
|
||||||
pop_scope()
|
pop_scope()
|
||||||
|
|
||||||
if not result[1] then
|
if not result[1] then
|
||||||
destroy()
|
destroy()
|
||||||
throw(`error while running root():\n\n{result[2]}`)
|
error(`error while running root():\n\n{result[2]}`, 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
return destroy, unpack(result :: any, 2)
|
return destroy, unpack(result :: any, 2)
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ export type Source<T> = (() -> T) & ((value: T) -> T)
|
||||||
local function source<T>(initial_value: T): Source<T>
|
local function source<T>(initial_value: T): Source<T>
|
||||||
local node = create_source_node(initial_value)
|
local node = create_source_node(initial_value)
|
||||||
|
|
||||||
return function(...): T
|
local function update_source(...): T
|
||||||
if select("#", ...) == 0 then -- no args were given
|
if select("#", ...) == 0 then -- no args were given
|
||||||
push_child_to_scope(node)
|
push_child_to_scope(node)
|
||||||
return node.cache
|
return node.cache
|
||||||
|
|
@ -24,6 +24,8 @@ local function source<T>(initial_value: T): Source<T>
|
||||||
update_descendants(node)
|
update_descendants(node)
|
||||||
return v
|
return v
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return update_source
|
||||||
end
|
end
|
||||||
|
|
||||||
return source :: (<T>(initial_value: T) -> Source<T>) & (<T>() -> Source<T>)
|
return source :: (<T>(initial_value: T) -> Source<T>) & (<T>() -> Source<T>)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
local throw = require "./throw"
|
|
||||||
local graph = require "./graph"
|
local graph = require "./graph"
|
||||||
type Node<T> = graph.Node<T>
|
type Node<T> = graph.Node<T>
|
||||||
type SourceNode<T> = graph.SourceNode<T>
|
type SourceNode<T> = graph.SourceNode<T>
|
||||||
|
|
@ -114,7 +113,7 @@ local vec6_to_type = {
|
||||||
|
|
||||||
local invalid_type = {
|
local invalid_type = {
|
||||||
__index = function(_, t: string)
|
__index = function(_, t: string)
|
||||||
throw(`cannot spring type {t}`)
|
error(`cannot spring type {t}`, 0)
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -141,7 +140,7 @@ local function spring<T>(source: () -> T, period: number?, damping_ratio: number
|
||||||
-- todo: is there a solution other than reducing step size?
|
-- todo: is there a solution other than reducing step size?
|
||||||
-- todo: this does not catch all solver exploding cases
|
-- todo: this does not catch all solver exploding cases
|
||||||
if c > UPDATE_RATE*2 then -- solver will explode if this is true
|
if c > UPDATE_RATE*2 then -- solver will explode if this is true
|
||||||
throw("spring damping too high, consider reducing damping or increasing period")
|
error("spring damping too high, consider reducing damping or increasing period", 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
local data: SpringState<T> = {
|
local data: SpringState<T> = {
|
||||||
|
|
@ -263,8 +262,6 @@ local function step_springs(dt: number)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local remove_queue = {}
|
|
||||||
|
|
||||||
local function update_spring_sources()
|
local function update_spring_sources()
|
||||||
for data, output in springs do
|
for data, output in springs do
|
||||||
local x0_123, x1_123, v_123,
|
local x0_123, x1_123, v_123,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
local throw = require "./throw"
|
|
||||||
local graph = require "./graph"
|
local graph = require "./graph"
|
||||||
type Node<T> = graph.Node<T>
|
type Node<T> = graph.Node<T>
|
||||||
type SourceNode<T> = graph.SourceNode<T>
|
type SourceNode<T> = graph.SourceNode<T>
|
||||||
|
|
@ -32,7 +31,7 @@ local function switch<T, U>(source: () -> T): (map: Map<T, ((() -> U)?)>) -> ()
|
||||||
if component == nil then return nil end
|
if component == nil then return nil end
|
||||||
|
|
||||||
if type(component) ~= "function" then
|
if type(component) ~= "function" then
|
||||||
throw "map must map a value to a function"
|
error "map must map a value to a function"
|
||||||
end
|
end
|
||||||
|
|
||||||
local new_scope = create_node(owner, false, false)
|
local new_scope = create_node(owner, false, false)
|
||||||
|
|
@ -40,7 +39,7 @@ local function switch<T, U>(source: () -> T): (map: Map<T, ((() -> U)?)>) -> ()
|
||||||
|
|
||||||
push_scope(new_scope)
|
push_scope(new_scope)
|
||||||
|
|
||||||
local ok, result = pcall(component)
|
local ok, result = xpcall(component, debug.traceback)
|
||||||
|
|
||||||
pop_scope()
|
pop_scope()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
local function VIDE_ASSERT(msg): any
|
|
||||||
error(msg, 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
return VIDE_ASSERT
|
|
||||||
|
|
@ -10,13 +10,13 @@ local function untrack<T>(source: () -> T): T
|
||||||
local effect = scope.effect
|
local effect = scope.effect
|
||||||
scope.effect = false
|
scope.effect = false
|
||||||
|
|
||||||
local ok, result = pcall(source)
|
local ok, result = xpcall(source, debug.traceback)
|
||||||
|
|
||||||
scope.effect = effect :: () -> ()
|
scope.effect = effect :: () -> ()
|
||||||
|
|
||||||
if not ok then error(result, 0) end
|
if not ok then error(result, 0) end
|
||||||
|
|
||||||
return result
|
return result :: T
|
||||||
else
|
else
|
||||||
return source()
|
return source()
|
||||||
end
|
end
|
||||||
|
|
|
||||||
110
test/stacktrace-test.luau
Normal file
110
test/stacktrace-test.luau
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
local vide = require "../"
|
||||||
|
|
||||||
|
do
|
||||||
|
print "============================================================="
|
||||||
|
|
||||||
|
local a = vide.source(1)
|
||||||
|
|
||||||
|
local cause_error = false
|
||||||
|
|
||||||
|
local function try_error()
|
||||||
|
if cause_error then error("uh oh") end
|
||||||
|
end
|
||||||
|
|
||||||
|
vide.root(function()
|
||||||
|
vide.effect(function()
|
||||||
|
a()
|
||||||
|
try_error()
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
cause_error = true
|
||||||
|
|
||||||
|
local ok, result = pcall(function() a(2) end)
|
||||||
|
print(result)
|
||||||
|
|
||||||
|
print "============================================================="
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
print "============================================================="
|
||||||
|
|
||||||
|
local a = vide.source(1)
|
||||||
|
local b = vide.source(1)
|
||||||
|
local c = vide.source(1)
|
||||||
|
|
||||||
|
local cause_error = false
|
||||||
|
|
||||||
|
local function try_error()
|
||||||
|
if cause_error then error("uh oh") end
|
||||||
|
end
|
||||||
|
|
||||||
|
vide.root(function()
|
||||||
|
vide.effect(function()
|
||||||
|
a()
|
||||||
|
b(vide.untrack(b) + 1)
|
||||||
|
end)
|
||||||
|
|
||||||
|
vide.effect(function()
|
||||||
|
b()
|
||||||
|
c(vide.untrack(c) + 1)
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
vide.effect(function()
|
||||||
|
c()
|
||||||
|
try_error()
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
cause_error = true
|
||||||
|
|
||||||
|
local ok, result = pcall(function() a(2) end)
|
||||||
|
print(result)
|
||||||
|
|
||||||
|
print "============================================================="
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
print "============================================================="
|
||||||
|
|
||||||
|
local a = vide.source(1)
|
||||||
|
local b = vide.source(1)
|
||||||
|
local c = vide.source(1)
|
||||||
|
|
||||||
|
local cause_error = false
|
||||||
|
|
||||||
|
local function try_error()
|
||||||
|
if cause_error then error("uh oh") end
|
||||||
|
end
|
||||||
|
|
||||||
|
vide.root(function()
|
||||||
|
vide.effect(function()
|
||||||
|
a()
|
||||||
|
vide.untrack(function() -- todo: this trace appearing twice
|
||||||
|
b(b() + 1)
|
||||||
|
return nil
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
vide.effect(function()
|
||||||
|
b()
|
||||||
|
vide.batch(function()
|
||||||
|
c(vide.untrack(c) + 1)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
vide.effect(function()
|
||||||
|
c()
|
||||||
|
try_error()
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
cause_error = true
|
||||||
|
|
||||||
|
local ok, result = pcall(function() a(2) end)
|
||||||
|
print(result)
|
||||||
|
|
||||||
|
print "============================================================="
|
||||||
|
end
|
||||||
Loading…
Add table
Add a link
Reference in a new issue