comptime eval
This commit is contained in:
@@ -567,6 +567,42 @@ main func() void {}
|
||||
testing.expect_value(t, module.exprs[chained.left].kind, ast.Expr_Kind.Negate)
|
||||
}
|
||||
|
||||
@(test)
|
||||
parser_accepts_comptime_prefix_and_block_expressions :: proc(t: ^testing.T) {
|
||||
text := `sum func(a, b int) int { return a + b }
|
||||
literal :: $32
|
||||
call :: $sum(1, 2) + 3
|
||||
block :: ${
|
||||
yield 4
|
||||
}
|
||||
main func() void {}
|
||||
`
|
||||
source_file := source.Source{path="test.bro", text=text}
|
||||
diagnostics := source.init_diagnostics(&source_file)
|
||||
defer source.destroy_diagnostics(&diagnostics)
|
||||
symbols := symbol.init_table()
|
||||
defer symbol.destroy_table(&symbols)
|
||||
stream := lexer.lex(&source_file, &diagnostics, &symbols)
|
||||
defer delete(stream.items)
|
||||
module := parser.parse(&stream, &source_file, &diagnostics)
|
||||
defer ast.destroy_module(&module)
|
||||
|
||||
literal := module.exprs[module.globals[0].expr]
|
||||
call_add := module.exprs[module.globals[1].expr]
|
||||
call := module.exprs[call_add.left]
|
||||
block := module.exprs[module.globals[2].expr]
|
||||
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
testing.expect_value(t, literal.kind, ast.Expr_Kind.Comptime)
|
||||
testing.expect_value(t, module.exprs[literal.left].kind, ast.Expr_Kind.Integer)
|
||||
testing.expect_value(t, call_add.kind, ast.Expr_Kind.Add)
|
||||
testing.expect_value(t, call.kind, ast.Expr_Kind.Comptime)
|
||||
testing.expect_value(t, module.exprs[call.left].kind, ast.Expr_Kind.Call)
|
||||
testing.expect_value(t, block.kind, ast.Expr_Kind.Comptime)
|
||||
testing.expect_value(t, len(block.body), 1)
|
||||
testing.expect_value(t, module.statements[block.body[0]].kind, ast.Stmt_Kind.Yield)
|
||||
}
|
||||
|
||||
nested_expression_source :: proc(call: bool, depth: int) -> string {
|
||||
builder := strings.builder_make()
|
||||
defer strings.builder_destroy(&builder)
|
||||
@@ -2235,6 +2271,119 @@ main func() void {
|
||||
testing.expect(t, found_assign)
|
||||
}
|
||||
|
||||
@(test)
|
||||
comptime_expression_forces_integer_evaluation :: proc(t: ^testing.T) {
|
||||
text := `sum func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
max func(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
nested func(value int) int {
|
||||
two :: 2
|
||||
return sum(value, two)
|
||||
}
|
||||
make_array func($N usize) [N]u8 {
|
||||
data [N]u8 = undefined
|
||||
return data
|
||||
}
|
||||
forced :: $sum(1, 2)
|
||||
main func() i32 {
|
||||
value i32 :: $sum(20, 22)
|
||||
choice i32 :: $max(9, 3)
|
||||
blocked i32 :: ${
|
||||
local :: 5
|
||||
yield sum(local, 6)
|
||||
}
|
||||
bytes [_]u8 :: make_array($nested(2))
|
||||
if forced != 3 {
|
||||
return 1
|
||||
}
|
||||
if value != 42 {
|
||||
return 2
|
||||
}
|
||||
if choice != 9 {
|
||||
return 3
|
||||
}
|
||||
if blocked != 11 {
|
||||
return 4
|
||||
}
|
||||
if bytes.len != 4 {
|
||||
return 5
|
||||
}
|
||||
return 0
|
||||
}
|
||||
`
|
||||
source_file := source.Source{path="test.bro", text=text}
|
||||
diagnostics := source.init_diagnostics(&source_file)
|
||||
defer source.destroy_diagnostics(&diagnostics)
|
||||
symbols := symbol.init_table()
|
||||
defer symbol.destroy_table(&symbols)
|
||||
stream := lexer.lex(&source_file, &diagnostics, &symbols)
|
||||
defer delete(stream.items)
|
||||
ast_module := parser.parse(&stream, &source_file, &diagnostics)
|
||||
defer ast.destroy_module(&ast_module)
|
||||
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
|
||||
defer hir.destroy_module(&hir_module)
|
||||
ir_module := lower.lower(&hir_module)
|
||||
defer ir.destroy_module(&ir_module)
|
||||
llvm_text := llvm.emit(&ir_module, &diagnostics, &symbols)
|
||||
defer delete(llvm_text)
|
||||
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
testing.expect(t, strings.contains(llvm_text, "@bro.g.0 = internal constant i8 3"))
|
||||
}
|
||||
|
||||
@(test)
|
||||
comptime_expression_diagnoses_unsupported_v1_evaluation :: proc(t: ^testing.T) {
|
||||
text := `loop func() int {
|
||||
while true {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
missing func() int {
|
||||
if true {
|
||||
}
|
||||
}
|
||||
recurse func(value int) int {
|
||||
return recurse(value)
|
||||
}
|
||||
main func() void {
|
||||
runtime i32 = 1
|
||||
_ = $runtime
|
||||
_ = $loop()
|
||||
_ = $missing()
|
||||
_ = $recurse(1)
|
||||
_ = ${
|
||||
value :: 1
|
||||
}
|
||||
}
|
||||
`
|
||||
source_file := source.Source{path="test.bro", text=text}
|
||||
diagnostics := source.init_diagnostics(&source_file)
|
||||
defer source.destroy_diagnostics(&diagnostics)
|
||||
symbols := symbol.init_table()
|
||||
defer symbol.destroy_table(&symbols)
|
||||
stream := lexer.lex(&source_file, &diagnostics, &symbols)
|
||||
defer delete(stream.items)
|
||||
ast_module := parser.parse(&stream, &source_file, &diagnostics)
|
||||
defer ast.destroy_module(&ast_module)
|
||||
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
|
||||
defer hir.destroy_module(&hir_module)
|
||||
|
||||
found := 0
|
||||
for diagnostic in diagnostics.items {
|
||||
if strings.contains(diagnostic.message, "expression cannot be evaluated at comptime") {
|
||||
found += 1
|
||||
}
|
||||
}
|
||||
testing.expect(t, found >= 5)
|
||||
}
|
||||
|
||||
@(test)
|
||||
unused_function_signatures_are_validated_eagerly :: proc(t: ^testing.T) {
|
||||
text := `broken func(value, value i8, nope void) void {}
|
||||
@@ -5615,6 +5764,16 @@ comptime_type_params_compile_and_run :: proc(t: ^testing.T) {
|
||||
testing.expect_value(t, state.exit_code, 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
comptime_eval_compile_and_run :: proc(t: ^testing.T) {
|
||||
output := "/tmp/brolang-test-comptime-eval"
|
||||
defer _ = os.remove(output)
|
||||
status := compiler_core.compile_package("examples/programs/comptime_eval", output)
|
||||
testing.expect_value(t, status, 0)
|
||||
state := run_executable(output)
|
||||
testing.expect_value(t, state.exit_code, 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
lazy_function_body_marks_import_as_used_without_resolving_it :: proc(t: ^testing.T) {
|
||||
output := "/tmp/brolang-test-package-lazy-import"
|
||||
|
||||
Reference in New Issue
Block a user