167 lines
4.7 KiB
Plaintext
167 lines
4.7 KiB
Plaintext
// Declaration restriction tests
|
|
// Run: ./cell tests/decl_restrictions.ce
|
|
|
|
var tokenize = use("tokenize")
|
|
var parse = use("parse")
|
|
|
|
var passed = 0
|
|
var failed = 0
|
|
var error_names = []
|
|
var error_reasons = []
|
|
var fail_msg = ""
|
|
|
|
var _i = 0
|
|
for (_i = 0; _i < 20; _i++) {
|
|
error_names[] = null
|
|
error_reasons[] = null
|
|
}
|
|
|
|
var fail = function(msg) {
|
|
fail_msg = msg
|
|
disrupt
|
|
}
|
|
|
|
var run = function(name, fn) {
|
|
fail_msg = ""
|
|
fn()
|
|
passed = passed + 1
|
|
} disruption {
|
|
error_names[failed] = name
|
|
error_reasons[failed] = fail_msg == "" ? "disruption" : fail_msg
|
|
failed = failed + 1
|
|
}
|
|
|
|
var parse_snippet = function(src) {
|
|
var result = tokenize(src, "<test>")
|
|
var ast = parse(result.tokens, src, "<test>", tokenize)
|
|
return ast
|
|
}
|
|
|
|
var has_error = function(ast, substring) {
|
|
if (ast.errors == null) return false
|
|
var i = 0
|
|
while (i < length(ast.errors)) {
|
|
if (search(ast.errors[i].message, substring) != null) return true
|
|
i = i + 1
|
|
}
|
|
return false
|
|
}
|
|
|
|
var has_no_errors = function(ast) {
|
|
return ast.errors == null || length(ast.errors) == 0
|
|
}
|
|
|
|
// === BARE BLOCK ===
|
|
|
|
run("bare block rejected", function() {
|
|
var ast = parse_snippet("{ var x = 1 }")
|
|
if (!has_error(ast, "bare block")) fail("expected 'bare block' error, got: " + text(ast.errors))
|
|
})
|
|
|
|
// === VAR IN IF (braces) ===
|
|
|
|
run("var in if braces", function() {
|
|
var ast = parse_snippet("if (true) { var x = 1 }")
|
|
if (!has_error(ast, "not inside 'if'")) fail("expected 'not inside if' error, got: " + text(ast.errors))
|
|
})
|
|
|
|
// === VAR IN IF (no braces) ===
|
|
|
|
run("var in if no braces", function() {
|
|
var ast = parse_snippet("if (true) var x = 1")
|
|
if (!has_error(ast, "not inside 'if'")) fail("expected 'not inside if' error, got: " + text(ast.errors))
|
|
})
|
|
|
|
// === VAR IN WHILE ===
|
|
|
|
run("var in while", function() {
|
|
var ast = parse_snippet("while (true) { var x = 1; break }")
|
|
if (!has_error(ast, "not inside 'while'")) fail("expected 'not inside while' error, got: " + text(ast.errors))
|
|
})
|
|
|
|
// === VAR IN FOR INIT ===
|
|
|
|
run("var in for init", function() {
|
|
var ast = parse_snippet("for (var i = 0; i < 1; i++) {}")
|
|
if (!has_error(ast, "for initializer")) fail("expected 'for initializer' error, got: " + text(ast.errors))
|
|
})
|
|
|
|
// === VAR IN FOR BODY ===
|
|
|
|
run("var in for body", function() {
|
|
var ast = parse_snippet("var i = 0; for (i = 0; i < 1; i++) { var x = 1 }")
|
|
if (!has_error(ast, "not inside 'for'")) fail("expected 'not inside for' error, got: " + text(ast.errors))
|
|
})
|
|
|
|
// === VAR IN DO ===
|
|
|
|
run("var in do", function() {
|
|
var ast = parse_snippet("do { var x = 1; break } while (true)")
|
|
if (!has_error(ast, "not inside 'do'")) fail("expected 'not inside do' error, got: " + text(ast.errors))
|
|
})
|
|
|
|
// === DEF IN IF ===
|
|
|
|
run("def in if", function() {
|
|
var ast = parse_snippet("if (true) { def x = 1 }")
|
|
if (!has_error(ast, "not inside 'if'")) fail("expected 'not inside if' error, got: " + text(ast.errors))
|
|
})
|
|
|
|
// === UNINITIALIZED VAR ===
|
|
|
|
run("uninitialized var", function() {
|
|
var ast = parse_snippet("var x")
|
|
if (!has_error(ast, "must be initialized")) fail("expected 'must be initialized' error, got: " + text(ast.errors))
|
|
})
|
|
|
|
// === NESTED: VAR IN IF INSIDE WHILE ===
|
|
|
|
run("nested var in if inside while", function() {
|
|
var ast = parse_snippet("while (true) { if (true) { var x = 1 }; break }")
|
|
if (!has_error(ast, "not inside 'if'")) fail("expected 'not inside if' error, got: " + text(ast.errors))
|
|
})
|
|
|
|
// === VALID: NESTED FUNCTION ===
|
|
|
|
run("valid nested fn in control flow", function() {
|
|
var ast = parse_snippet("if (true) { var fn = function() { var x = 1; return x } }")
|
|
// The var inside the function is fine; only the var fn = ... inside if should error
|
|
if (!has_error(ast, "not inside 'if'")) fail("expected error for var fn inside if")
|
|
// But there should NOT be an error about var x inside the function body
|
|
var i = 0
|
|
var bad = false
|
|
if (ast.errors != null) {
|
|
while (i < length(ast.errors)) {
|
|
if (search(ast.errors[i].message, "var x") != null) bad = true
|
|
i = i + 1
|
|
}
|
|
}
|
|
if (bad) fail("should not error on var inside nested function")
|
|
})
|
|
|
|
// === VALID: NORMAL VAR ===
|
|
|
|
run("valid normal var", function() {
|
|
var ast = parse_snippet("var x = 1")
|
|
if (!has_no_errors(ast)) fail("expected no errors, got: " + text(ast.errors))
|
|
})
|
|
|
|
// === VALID: VAR IN FUNCTION BODY ===
|
|
|
|
run("valid var in function body", function() {
|
|
var ast = parse_snippet("var fn = function() { var x = 1; return x }")
|
|
if (!has_no_errors(ast)) fail("expected no errors, got: " + text(ast.errors))
|
|
})
|
|
|
|
// === SUMMARY ===
|
|
|
|
print(text(passed) + " passed, " + text(failed) + " failed out of " + text(passed + failed))
|
|
var _j = 0
|
|
if (failed > 0) {
|
|
print("")
|
|
for (_j = 0; _j < failed; _j++) {
|
|
print(" FAIL " + error_names[_j] + ": " + error_reasons[_j])
|
|
}
|
|
}
|
|
$stop()
|