mirror of
https://github.com/leporello-js/leporello-js
synced 2026-01-13 13:04:30 -08:00
not iterable error
This commit is contained in:
@@ -145,20 +145,30 @@ export const find_node = (node, pred) => {
|
||||
)
|
||||
}
|
||||
|
||||
// TODO refactor, have explicit information if node is error origin, without
|
||||
// guessing. See also color.js
|
||||
// TODO check if return result is null and throw early
|
||||
export const find_error_origin_node = node =>
|
||||
find_node(
|
||||
// TODO do not go inside function_expr
|
||||
node,
|
||||
n => n.result != null && !n.result.ok && (
|
||||
n.result.error != null
|
||||
||
|
||||
// In case if throw null or throw undefined
|
||||
n.type == 'throw'
|
||||
||
|
||||
// await can also throw null
|
||||
n.type == 'unary' && n.operator == 'await'
|
||||
// or function call throwing null or undefined
|
||||
||
|
||||
n.type == 'function_call'
|
||||
// node has no error, but its children also have no error, so this node
|
||||
// is error origin
|
||||
n.children.find(c => find_error_origin_node(c) != null) == null
|
||||
&&
|
||||
(
|
||||
// In case if throw null or throw undefined
|
||||
n.type == 'throw'
|
||||
||
|
||||
// await can also throw null
|
||||
n.type == 'unary' && n.operator == 'await'
|
||||
// or function call throwing null or undefined
|
||||
||
|
||||
n.type == 'function_call'
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ const node_to_color = node => ({
|
||||
? null
|
||||
: node.result.ok
|
||||
? {ok: true}
|
||||
// node.result.error may be null, for example if throw null
|
||||
// See find_error_origin_node
|
||||
: node.result.error == null
|
||||
? {ok: false, error_origin: false}
|
||||
: {ok: false, error_origin: true}
|
||||
|
||||
27
src/eval.js
27
src/eval.js
@@ -171,7 +171,7 @@ const codegen = (node, node_cxt, parent) => {
|
||||
} else if(node.type == 'object_literal'){
|
||||
const elements =
|
||||
node.elements.map(el => {
|
||||
if(el.type == 'spread'){
|
||||
if(el.type == 'object_spread'){
|
||||
return do_codegen(el)
|
||||
} else if(el.type == 'identifier') {
|
||||
return el.value
|
||||
@@ -241,7 +241,7 @@ const codegen = (node, node_cxt, parent) => {
|
||||
+ node.operator
|
||||
+ ' '
|
||||
+ do_codegen(node.args[1])
|
||||
} else if(node.type == 'spread'){
|
||||
} else if(node.type == 'array_spread' || node.type == 'object_spread'){
|
||||
return '...(' + do_codegen(node.expr) + ')'
|
||||
} else if(node.type == 'new') {
|
||||
const args = `[${node.args.children.map(do_codegen).join(',')}]`
|
||||
@@ -510,8 +510,24 @@ const do_eval_frame_expr = (node, scope, callsleft, context) => {
|
||||
// TODO exprs inside backtick string
|
||||
// Pass scope for backtick string
|
||||
return {...eval_codestring(node.value, scope), calls: callsleft}
|
||||
} else if(node.type == 'array_spread') {
|
||||
const result = eval_children(node, scope, callsleft, context)
|
||||
if(!result.ok) {
|
||||
return result
|
||||
}
|
||||
const child = result.children[0]
|
||||
if((typeof(child.result.value?.[Symbol.iterator])) == 'function') {
|
||||
return result
|
||||
} else {
|
||||
return {
|
||||
ok: false,
|
||||
children: result.children,
|
||||
calls: result.calls,
|
||||
error: new TypeError(child.string + ' is not iterable'),
|
||||
}
|
||||
}
|
||||
} else if([
|
||||
'spread',
|
||||
'object_spread',
|
||||
'key_value_pair',
|
||||
'computed_property'
|
||||
].includes(node.type)) {
|
||||
@@ -523,8 +539,7 @@ const do_eval_frame_expr = (node, scope, callsleft, context) => {
|
||||
}
|
||||
const value = children.reduce(
|
||||
(arr, el) => {
|
||||
if(el.type == 'spread') {
|
||||
// TODO check if iterable and throw error
|
||||
if(el.type == 'array_spread') {
|
||||
return [...arr, ...el.children[0].result.value]
|
||||
} else {
|
||||
return [...arr, el.result.value]
|
||||
@@ -540,7 +555,7 @@ const do_eval_frame_expr = (node, scope, callsleft, context) => {
|
||||
}
|
||||
const value = children.reduce(
|
||||
(value, el) => {
|
||||
if(el.type == 'spread'){
|
||||
if(el.type == 'object_spread'){
|
||||
return {...value, ...el.children[0].result.value}
|
||||
} else if(el.type == 'identifier') {
|
||||
// TODO check that it works
|
||||
|
||||
@@ -828,7 +828,12 @@ const array_element = either(
|
||||
literal('...'),
|
||||
cxt => expr(cxt),
|
||||
]),
|
||||
({value, ...node}) => ({...node, type: 'spread', not_evaluatable: true, children: [value]})
|
||||
({value, ...node}) => ({
|
||||
...node,
|
||||
type: 'array_spread',
|
||||
not_evaluatable: true,
|
||||
children: [value]
|
||||
})
|
||||
),
|
||||
cxt => expr(cxt),
|
||||
)
|
||||
@@ -857,7 +862,12 @@ const object_literal =
|
||||
literal('...'),
|
||||
cxt => expr(cxt),
|
||||
]),
|
||||
({value, ...node}) => ({...node, type: 'spread', children: [value], not_evaluatable: true})
|
||||
({value, ...node}) => ({
|
||||
...node,
|
||||
type: 'object_spread',
|
||||
children: [value],
|
||||
not_evaluatable: true
|
||||
})
|
||||
),
|
||||
|
||||
// Or key-value pair
|
||||
@@ -1456,7 +1466,7 @@ const update_children_not_rec = (node, children = node.children) => {
|
||||
}
|
||||
} else if(node.type == 'call_args') {
|
||||
return node
|
||||
} else if(node.type == 'spread') {
|
||||
} else if(node.type == 'array_spread' || node.type == 'object_spread') {
|
||||
return {...node,
|
||||
expr: children[0],
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user