This commit is contained in:
Dmitry Vasilev
2023-06-15 23:42:54 +03:00
parent bfc4f8d440
commit fdbe01249d
3 changed files with 46 additions and 71 deletions

View File

@@ -414,16 +414,6 @@ const assign_code = (modules, call) => {
} }
export const eval_tree = node => {
return eval_modules(
{
modules: {'': node},
sorted: ['']
}
).calltree
}
/* ------------- Metacircular interpreter ---------------------------- */ /* ------------- Metacircular interpreter ---------------------------- */
/* /*

View File

@@ -1,6 +1,6 @@
import {find_leaf, ancestry, find_node} from '../src/ast_utils.js' import {find_leaf, ancestry, find_node} from '../src/ast_utils.js'
import {parse, print_debug_node} from '../src/parse_js.js' import {parse, print_debug_node} from '../src/parse_js.js'
import {eval_tree, eval_frame, eval_modules} from '../src/eval.js' import {eval_frame, eval_modules} from '../src/eval.js'
import {COMMANDS} from '../src/cmd.js' import {COMMANDS} from '../src/cmd.js'
import { import {
root_calltree_node, root_calltree_node,
@@ -15,6 +15,7 @@ import {
test_only, test_only,
assert_equal, assert_equal,
stringify, stringify,
eval_tree,
assert_code_evals_to, assert_code_evals_to_async, assert_code_evals_to, assert_code_evals_to_async,
assert_code_error, assert_code_error_async, assert_code_error, assert_code_error_async,
parse_modules, parse_modules,
@@ -53,9 +54,7 @@ export const tests = [
}), }),
test('empty program', () => { test('empty program', () => {
const parse_result = parse('') const tree = eval_tree('')
assert_equal(parse_result.ok, true)
const tree = eval_tree(parse_result.node)
const frame = eval_frame(tree) const frame = eval_frame(tree)
assert_equal(frame.children, []) assert_equal(frame.children, [])
assert_equal(frame.result, {ok: true}) assert_equal(frame.result, {ok: true})
@@ -76,9 +75,7 @@ export const tests = [
}), }),
test('Only semicolons', () => { test('Only semicolons', () => {
const parse_result = parse(';;;;') const tree = eval_tree(';;;;')
assert_equal(parse_result.ok, true)
const tree = eval_tree(parse_result.node)
const frame = eval_frame(tree) const frame = eval_frame(tree)
assert_equal(frame.children, []) assert_equal(frame.children, [])
assert_equal(frame.result, {ok: true}) assert_equal(frame.result, {ok: true})
@@ -167,14 +164,13 @@ export const tests = [
}), }),
test('closure', () => { test('closure', () => {
const parsed = parse( const tree = eval_tree(
` `
const x = 1 const x = 1
const y = () => x; const y = () => x;
y() y()
` `
) )
const tree = eval_tree(parsed.node)
const frame = eval_frame(tree.children[0]) const frame = eval_frame(tree.children[0])
assert_equal(frame.children[1].result.value, 1) assert_equal(frame.children[1].result.value, 1)
}), }),
@@ -362,30 +358,23 @@ export const tests = [
}), }),
test('out of order decl', () => { test('out of order decl', () => {
const code = const tree = eval_tree( `
` const y = () => x;
const y = () => x; const x = 1;
const x = 1; y();
y(); `)
`
const parsed = parse(code)
assert_equal(parsed.ok, true)
const tree = eval_tree(parsed.node)
assert_equal(tree.children[0].value, 1) assert_equal(tree.children[0].value, 1)
}), }),
test('nested closure', () => { test('nested closure', () => {
const code = assert_code_evals_to(
` `
const x = () => () => y; const x = () => () => y
x(); const y = 1
const y = 1; x()()
` `,
const parsed = parse(code) 1
assert_equal(parsed.ok, true) )
const tree = eval_tree(parsed.node)
assert_equal(tree.ok, true)
// TODO assert
}), }),
test('Simple expression ASI', () => { test('Simple expression ASI', () => {
@@ -668,10 +657,9 @@ export const tests = [
}), }),
test('eval_frame binary', () => { test('eval_frame binary', () => {
const parsed = parse(` const tree = eval_tree(`
1 + 1 1 + 1
`) `)
const tree = eval_tree(parsed.node)
assert_equal(eval_frame(tree).children[0].result.value, 2) assert_equal(eval_frame(tree).children[0].result.value, 2)
}), }),
@@ -681,50 +669,44 @@ export const tests = [
}), }),
test('eval_frame grouping', () => { test('eval_frame grouping', () => {
const parsed = parse('(1+1)') const tree = eval_tree('(1+1)')
const tree = eval_tree(parsed.node)
assert_equal(eval_frame(tree).children[0].result.value, 2) assert_equal(eval_frame(tree).children[0].result.value, 2)
}), }),
test('eval_frame member_access', () => { test('eval_frame member_access', () => {
const parsed = parse('{foo: "bar"}["foo"]') const tree = eval_tree('{foo: "bar"}["foo"]')
const tree = eval_tree(parsed.node)
assert_equal(eval_frame(tree).children[0].result.value, 'bar') assert_equal(eval_frame(tree).children[0].result.value, 'bar')
}), }),
test('eval_frame new', () => { test('eval_frame new', () => {
const parsed = parse('new Error("foobar")') const tree = eval_tree('new Error("foobar")')
const tree = eval_tree(parsed.node)
assert_equal(eval_frame(tree).children[0].result.value.message, 'foobar') assert_equal(eval_frame(tree).children[0].result.value.message, 'foobar')
}), }),
test('eval_frame function_call', () => { test('eval_frame function_call', () => {
const parsed = parse(` const tree = eval_tree(`
const x = () => 1; const x = () => 1;
2 * x(); 2 * x();
`) `)
const tree = eval_tree(parsed.node)
assert_equal(eval_frame(tree).children[1].result.value, 2) assert_equal(eval_frame(tree).children[1].result.value, 2)
}), }),
test('eval_frame function_body_expr', () => { test('eval_frame function_body_expr', () => {
const parsed = parse(` const tree = eval_tree(`
const x = y => y; const x = y => y;
x(2); x(2);
`) `)
const tree = eval_tree(parsed.node)
assert_equal(eval_frame(tree.children[0]).children[1].result, {ok: true, value: 2}) assert_equal(eval_frame(tree.children[0]).children[1].result, {ok: true, value: 2})
}), }),
test('eval_frame function_body_do', () => { test('eval_frame function_body_do', () => {
const parsed = parse(` const tree = eval_tree(`
const x = y => { const x = y => {
return y; return y;
const z = 1; const z = 1;
}; };
x(2); x(2);
`) `)
const tree = eval_tree(parsed.node)
const frame = eval_frame(tree.children[0]) const frame = eval_frame(tree.children[0])
const ret = frame.children[1].children[0] const ret = frame.children[1].children[0]
const z_after_ret = frame.children[1].children[1] const z_after_ret = frame.children[1].children[1]
@@ -733,14 +715,13 @@ export const tests = [
}), }),
test('eval_frame if', () => { test('eval_frame if', () => {
const parsed = parse(` const tree = eval_tree(`
if(1) { if(1) {
const x = 1; const x = 1;
} else { } else {
const x = 1; const x = 1;
} }
`) `)
const tree = eval_tree(parsed.node)
const frame = eval_frame(tree) const frame = eval_frame(tree)
const _if = frame.children[0] const _if = frame.children[0]
assert_equal(_if.children[0].result, {ok: true, value: 1}) assert_equal(_if.children[0].result, {ok: true, value: 1})
@@ -749,12 +730,11 @@ export const tests = [
}), }),
test('eval_frame if without else', () => { test('eval_frame if without else', () => {
const parsed = parse(` const tree = eval_tree(`
if(1) { if(1) {
const x = 1; const x = 1;
} }
`) `)
const tree = eval_tree(parsed.node)
const frame = eval_frame(tree) const frame = eval_frame(tree)
const _if = frame.children[0] const _if = frame.children[0]
assert_equal(_if.children.length, 2) assert_equal(_if.children.length, 2)
@@ -777,71 +757,64 @@ export const tests = [
}), }),
test('eval_frame error', () => { test('eval_frame error', () => {
const parsed = parse(` const tree = eval_tree(`
const x = ({a}) => 0; const x = ({a}) => 0;
x(null); x(null);
`) `)
const tree = eval_tree(parsed.node)
const frame = eval_frame(tree.children[0]) const frame = eval_frame(tree.children[0])
assert_equal(frame.result, {ok: false}) assert_equal(frame.result, {ok: false})
}), }),
test('eval_frame binary &&', () => { test('eval_frame binary &&', () => {
const parsed = parse(` const tree = eval_tree(`
const x = () => 1; const x = () => 1;
const y = () => 2; const y = () => 2;
false && x(); false && x();
y(); y();
`) `)
const tree = eval_tree(parsed.node)
const frame = eval_frame(tree) const frame = eval_frame(tree)
assert_equal(frame.children[3].result.value, 2) assert_equal(frame.children[3].result.value, 2)
}), }),
test('eval_frame binary ||', () => { test('eval_frame binary ||', () => {
const parsed = parse(` const tree = eval_tree(`
const x = () => 1; const x = () => 1;
const y = () => 2; const y = () => 2;
true || x(); true || x();
y(); y();
`) `)
const tree = eval_tree(parsed.node)
const frame = eval_frame(tree) const frame = eval_frame(tree)
assert_equal(frame.children[3].result.value, 2) assert_equal(frame.children[3].result.value, 2)
}), }),
test('eval_frame binary ??', () => { test('eval_frame binary ??', () => {
const parsed = parse(` const tree = eval_tree(`
const x = () => 1; const x = () => 1;
const y = () => 2; const y = () => 2;
1 ?? x(); 1 ?? x();
y(); y();
`) `)
const tree = eval_tree(parsed.node)
const frame = eval_frame(tree) const frame = eval_frame(tree)
assert_equal(frame.children[3].result.value, 2) assert_equal(frame.children[3].result.value, 2)
}), }),
test('eval_frame null call', () => { test('eval_frame null call', () => {
const parsed = parse(`null()`) const tree = eval_tree(`null()`)
const tree = eval_tree(parsed.node)
const frame = eval_frame(tree) const frame = eval_frame(tree)
assert_equal(frame.children[0].result.ok, false) assert_equal(frame.children[0].result.ok, false)
}), }),
test('eval_frame non-function call bug', () => { test('eval_frame non-function call bug', () => {
const parsed = parse(`Object.assign({}, {}); null()`) const tree = eval_tree(`Object.assign({}, {}); null()`)
const tree = eval_tree(parsed.node)
const frame = eval_frame(tree) const frame = eval_frame(tree)
assert_equal(frame.children[frame.children.length - 1].result.ok, false) assert_equal(frame.children[frame.children.length - 1].result.ok, false)
}), }),
test('eval_frame destructuring args', () => { test('eval_frame destructuring args', () => {
const parsed = parse(` const tree = eval_tree(`
const x = (...a) => a; const x = (...a) => a;
x(1,2,3); x(1,2,3);
`) `)
const tree = eval_tree(parsed.node)
const frame = eval_frame(tree.children[0]) const frame = eval_frame(tree.children[0])
assert_equal(frame.children[0].children[0].children[0].result.value, [1,2,3]) assert_equal(frame.children[0].children[0].children[0].result.value, [1,2,3])
}), }),

View File

@@ -1,4 +1,5 @@
import {print_debug_node, load_modules} from '../src/parse_js.js' import {parse, print_debug_node, load_modules} from '../src/parse_js.js'
import {eval_modules} from '../src/eval.js'
import {active_frame, pp_calltree} from '../src/calltree.js' import {active_frame, pp_calltree} from '../src/calltree.js'
import {COMMANDS} from '../src/cmd.js' import {COMMANDS} from '../src/cmd.js'
@@ -48,6 +49,17 @@ export const original_setTimeout = globalThis.run_window.__original_setTimeout
export const parse_modules = (entry, modules) => export const parse_modules = (entry, modules) =>
load_modules(entry, module_name => modules[module_name]) load_modules(entry, module_name => modules[module_name])
export const eval_tree = code => {
const parse_result = parse(code)
assert_equal(parse_result.ok, true)
return eval_modules(
{
modules: {'': parse_result.node},
sorted: ['']
}
).calltree
}
export const assert_code_evals_to = (codestring, expected) => { export const assert_code_evals_to = (codestring, expected) => {
const s = test_initial_state(codestring) const s = test_initial_state(codestring)
const frame = active_frame(s) const frame = active_frame(s)