mirror of
https://github.com/leporello-js/leporello-js
synced 2026-01-13 13:04:30 -08:00
fixed name declared twice
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
// TODO rename to analyze.js
|
||||
|
||||
import {set_push, set_diff, set_union, map_object, map_find, uniq} from './utils.js'
|
||||
import {collect_destructuring_identifiers, collect_imports, ancestry, find_leaf} from './ast_utils.js'
|
||||
import {set_push, set_diff, set_union, map_object, map_find, uniq, uniq_by}
|
||||
from './utils.js'
|
||||
import {collect_destructuring_identifiers, collect_imports, ancestry, find_leaf}
|
||||
from './ast_utils.js'
|
||||
|
||||
const map_find_definitions = (nodes, mapper) => {
|
||||
const result = nodes.map(mapper)
|
||||
@@ -305,9 +307,27 @@ const analyze_await = (node, is_async_context = true) => {
|
||||
return result ?? []
|
||||
}
|
||||
|
||||
const find_duplicates = names => {
|
||||
const duplicates = names.filter((n, i) =>
|
||||
names.find((name, j) => name.value == n.value && j < i) != null
|
||||
)
|
||||
const problems = duplicates.map(d => ({
|
||||
index: d.index,
|
||||
length: d.length,
|
||||
message: `Identifier '${d.value}' has already been declared`,
|
||||
}))
|
||||
return problems
|
||||
}
|
||||
|
||||
const named_declared_once = node => {
|
||||
return collect_problems(node, null, (node, cxt) => {
|
||||
if(node.type == 'do') {
|
||||
if(node.type == 'function_expr') {
|
||||
const names = collect_destructuring_identifiers(node.function_args)
|
||||
return {
|
||||
context: uniq_by(names, n => n.value),
|
||||
problems: find_duplicates(names),
|
||||
}
|
||||
} else if(node.type == 'do') {
|
||||
const names = node
|
||||
.children
|
||||
.map(c => {
|
||||
@@ -327,14 +347,9 @@ const named_declared_once = node => {
|
||||
})
|
||||
.flat()
|
||||
.filter(n => n != null)
|
||||
const duplicates = names.filter((n, i) =>
|
||||
names.find((name, j) => name.value == n.value && j < i) != null
|
||||
const problems = find_duplicates(
|
||||
[...(cxt ?? []), ...names]
|
||||
)
|
||||
const problems = duplicates.map(d => ({
|
||||
index: d.index,
|
||||
length: d.length,
|
||||
message: `Identifier '${d.value}' has already been declared`,
|
||||
}))
|
||||
return {context: null, problems}
|
||||
} else {
|
||||
return {context: null, problems: null}
|
||||
|
||||
@@ -53,6 +53,13 @@ export const zip = (x,y) => {
|
||||
|
||||
export const uniq = arr => [...new Set(arr)]
|
||||
|
||||
export const uniq_by = (arr, mapper) => [
|
||||
...new Map(
|
||||
arr.map(e => [mapper(e), e])
|
||||
)
|
||||
.values()
|
||||
]
|
||||
|
||||
export const collect_nodes_with_parents = new Function('node', 'pred', `
|
||||
const result = []
|
||||
|
||||
|
||||
43
test/test.js
43
test/test.js
@@ -1269,6 +1269,49 @@ export const tests = [
|
||||
]
|
||||
)
|
||||
}),
|
||||
|
||||
test('identifier has already been declared in fn arg', () => {
|
||||
const code = `
|
||||
function foo(x) {
|
||||
const x = 1
|
||||
}
|
||||
|
||||
`
|
||||
const i = test_initial_state(code)
|
||||
assert_equal(i.parse_result.ok, false)
|
||||
assert_equal(
|
||||
i.parse_result.problems,
|
||||
[
|
||||
{
|
||||
index: code.indexOf('x = 1'),
|
||||
length: 1,
|
||||
message: "Identifier 'x' has already been declared",
|
||||
module: '',
|
||||
}
|
||||
]
|
||||
)
|
||||
}),
|
||||
|
||||
test('identifier has been declared twice in args', () => {
|
||||
const code = `
|
||||
function foo({x,x}) {
|
||||
}
|
||||
|
||||
`
|
||||
const i = test_initial_state(code)
|
||||
assert_equal(i.parse_result.ok, false)
|
||||
assert_equal(
|
||||
i.parse_result.problems,
|
||||
[
|
||||
{
|
||||
index: code.indexOf('x}'),
|
||||
length: 1,
|
||||
message: "Identifier 'x' has already been declared",
|
||||
module: '',
|
||||
}
|
||||
]
|
||||
)
|
||||
}),
|
||||
|
||||
test('identifier has already been declared fn decl', () => {
|
||||
const code = `
|
||||
|
||||
Reference in New Issue
Block a user