Add break & continue statements
This commit is contained in:
parent
356eea4fb8
commit
06d509bcab
13 changed files with 246 additions and 104 deletions
|
|
@ -573,11 +573,13 @@ func raytrace(scene: scene*, camera_ray: ray, rng: rng mut*) -> vec3:
|
|||
mut factor = vec3(1.0, 1.0, 1.0)
|
||||
let termination_probability = 0.25
|
||||
|
||||
mut running = true
|
||||
while running:
|
||||
while true:
|
||||
let intersection = intersect_scene(scene, current_ray)
|
||||
|
||||
if intersection.intersected:
|
||||
if !intersection.intersected:
|
||||
result = add(result, multv(factor, (*scene).background))
|
||||
break
|
||||
|
||||
// Uncomment to debug normals
|
||||
// return mults(add(intersection.normal, vec3(1.0, 1.0, 1.0)), 0.5)
|
||||
|
||||
|
|
@ -588,9 +590,8 @@ func raytrace(scene: scene*, camera_ray: ray, rng: rng mut*) -> vec3:
|
|||
|
||||
// Russian roulette ray termination
|
||||
if next_f32(rng) < termination_probability:
|
||||
// No break operator yet...
|
||||
running = false
|
||||
else:
|
||||
break
|
||||
|
||||
mut new_direction = vec3(0.0, 0.0, 0.0)
|
||||
|
||||
if (*intersection.material).type == diffuse_tag:
|
||||
|
|
@ -642,9 +643,6 @@ func raytrace(scene: scene*, camera_ray: ray, rng: rng mut*) -> vec3:
|
|||
|
||||
// Account for Russian roulette
|
||||
factor = mults(factor, 1.0 / (1.0 - termination_probability))
|
||||
else:
|
||||
result = add(result, multv(factor, (*scene).background))
|
||||
running = false
|
||||
|
||||
return result
|
||||
|
||||
|
|
@ -777,8 +775,8 @@ const default_fovy = 2.0 * atan(0.5)
|
|||
func main():
|
||||
let scene = make_default_scene()
|
||||
|
||||
let image = create_image(512ul, 512ul)
|
||||
// let image = create_image(256ul, 256ul)
|
||||
// let image = create_image(512ul, 512ul)
|
||||
let image = create_image(256ul, 256ul)
|
||||
// let image = create_image(128ul, 128ul)
|
||||
|
||||
let aspect_ratio = (image.width as f32) / (image.height as f32)
|
||||
|
|
@ -865,7 +863,9 @@ func main():
|
|||
sleep(timespec(0l, 125000000l))
|
||||
let time = get_time()
|
||||
let delta = time_delta(time, last_report_time)
|
||||
if delta > 0.125 || last_report_progress == 0.0:
|
||||
if !(delta > 0.125 || last_report_progress == 0.0):
|
||||
continue
|
||||
|
||||
done = 0ul
|
||||
|
||||
mut th = 0ul
|
||||
|
|
@ -875,7 +875,9 @@ func main():
|
|||
unlock_mutex(threads_data[th].done_mutex)
|
||||
th += 1ul
|
||||
|
||||
if done > 0ul:
|
||||
if done == 0ul:
|
||||
continue
|
||||
|
||||
let progress = (done as f32) / (total as f32)
|
||||
|
||||
// Running exponential-weighted average speed
|
||||
|
|
|
|||
|
|
@ -49,4 +49,14 @@ namespace pslang::ast
|
|||
location location;
|
||||
};
|
||||
|
||||
struct break_statement
|
||||
{
|
||||
location location;
|
||||
};
|
||||
|
||||
struct continue_statement
|
||||
{
|
||||
location location;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ namespace pslang::ast
|
|||
else_block,
|
||||
else_if_block,
|
||||
while_block,
|
||||
break_statement,
|
||||
continue_statement,
|
||||
function_definition,
|
||||
foreign_function_declaration,
|
||||
return_statement,
|
||||
|
|
@ -47,6 +49,8 @@ namespace pslang::ast
|
|||
variable_declaration,
|
||||
if_chain,
|
||||
while_block,
|
||||
break_statement,
|
||||
continue_statement,
|
||||
function_definition,
|
||||
foreign_function_declaration,
|
||||
return_statement,
|
||||
|
|
|
|||
|
|
@ -434,6 +434,18 @@ namespace pslang::ast
|
|||
child(*node.statements);
|
||||
}
|
||||
|
||||
void apply(break_statement const & node)
|
||||
{
|
||||
put_indent(out, options);
|
||||
out << "break\n";
|
||||
}
|
||||
|
||||
void apply(continue_statement const & node)
|
||||
{
|
||||
put_indent(out, options);
|
||||
out << "continue\n";
|
||||
}
|
||||
|
||||
void apply(function_definition const & node)
|
||||
{
|
||||
put_indent(out, options);
|
||||
|
|
|
|||
|
|
@ -84,6 +84,12 @@ namespace pslang::ast
|
|||
void apply(while_block const &)
|
||||
{}
|
||||
|
||||
void apply(break_statement const &)
|
||||
{}
|
||||
|
||||
void apply(continue_statement const &)
|
||||
{}
|
||||
|
||||
void apply(function_definition & function_definition)
|
||||
{
|
||||
if (scopes.back().contains(function_definition.name))
|
||||
|
|
@ -321,6 +327,12 @@ namespace pslang::ast
|
|||
scopes.pop_back();
|
||||
}
|
||||
|
||||
void apply(break_statement const & break_statement)
|
||||
{}
|
||||
|
||||
void apply(continue_statement const & continue_statement)
|
||||
{}
|
||||
|
||||
void apply(function_definition & function_definition)
|
||||
{
|
||||
// Already added to scope by populate_globals_visitor
|
||||
|
|
|
|||
|
|
@ -180,6 +180,12 @@ namespace pslang::ast
|
|||
void apply(while_block const &)
|
||||
{}
|
||||
|
||||
void apply(break_statement const &)
|
||||
{}
|
||||
|
||||
void apply(continue_statement const &)
|
||||
{}
|
||||
|
||||
void apply(function_definition & node)
|
||||
{
|
||||
types::function_type function_type;
|
||||
|
|
@ -866,6 +872,12 @@ namespace pslang::ast
|
|||
apply(*node.statements);
|
||||
}
|
||||
|
||||
void apply(break_statement const &)
|
||||
{}
|
||||
|
||||
void apply(continue_statement const &)
|
||||
{}
|
||||
|
||||
void apply(function_definition & node)
|
||||
{
|
||||
apply(*node.statements);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,12 @@ namespace pslang::ast
|
|||
apply(*node.statements);
|
||||
}
|
||||
|
||||
void apply(break_statement const &)
|
||||
{}
|
||||
|
||||
void apply(continue_statement const &)
|
||||
{}
|
||||
|
||||
void apply(function_definition const & node)
|
||||
{
|
||||
apply(*node.statements);
|
||||
|
|
|
|||
|
|
@ -139,6 +139,16 @@ namespace pslang::interpreter
|
|||
}
|
||||
}
|
||||
|
||||
void exec_impl(context & context, ast::break_statement const &)
|
||||
{
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
void exec_impl(context & context, ast::continue_statement const &)
|
||||
{
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
void exec_impl(context & context, ast::function_definition const & function_definition)
|
||||
{
|
||||
auto & frame = context.frame_stack.back();
|
||||
|
|
|
|||
|
|
@ -24,6 +24,15 @@ namespace pslang::ir
|
|||
|
||||
std::vector<scope> scopes;
|
||||
|
||||
struct loop_scope
|
||||
{
|
||||
// These must point to jump nodes
|
||||
std::vector<node_ref> resolve_break;
|
||||
std::vector<node_ref> resolve_continue;
|
||||
};
|
||||
|
||||
std::vector<loop_scope> loop_scopes;
|
||||
|
||||
struct resolve_address_data
|
||||
{
|
||||
node_ref address;
|
||||
|
|
@ -655,15 +664,39 @@ namespace pslang::ir
|
|||
auto begin = last();
|
||||
auto condition = apply(*node.condition);
|
||||
mcontext.nodes->emplace_back(jump_if_zero{condition, {}});
|
||||
auto jump1 = last();
|
||||
auto jump_to_end = last();
|
||||
|
||||
lcontext.loop_scopes.emplace_back();
|
||||
lcontext.scopes.emplace_back();
|
||||
apply(*node.statements);
|
||||
lcontext.scopes.pop_back();
|
||||
|
||||
mcontext.nodes->emplace_back(jump{begin});
|
||||
mcontext.nodes->emplace_back(label{});
|
||||
std::get<jump_if_zero>(jump1->instruction).target = last();
|
||||
|
||||
auto end = last();
|
||||
std::get<jump_if_zero>(jump_to_end->instruction).target = end;
|
||||
|
||||
for (auto node : lcontext.loop_scopes.back().resolve_continue)
|
||||
std::get<jump>(node->instruction).target = begin;
|
||||
for (auto node : lcontext.loop_scopes.back().resolve_break)
|
||||
std::get<jump>(node->instruction).target = end;
|
||||
lcontext.loop_scopes.pop_back();
|
||||
|
||||
return last();
|
||||
}
|
||||
|
||||
node_ref apply(ast::break_statement const &)
|
||||
{
|
||||
mcontext.nodes->emplace_back(jump{});
|
||||
lcontext.loop_scopes.back().resolve_break.push_back(last());
|
||||
return last();
|
||||
}
|
||||
|
||||
node_ref apply(ast::continue_statement const &)
|
||||
{
|
||||
mcontext.nodes->emplace_back(jump{});
|
||||
lcontext.loop_scopes.back().resolve_continue.push_back(last());
|
||||
return last();
|
||||
}
|
||||
|
||||
|
|
@ -759,6 +792,12 @@ namespace pslang::ir
|
|||
lcontext.scopes.pop_back();
|
||||
}
|
||||
|
||||
void apply(ast::break_statement const &)
|
||||
{}
|
||||
|
||||
void apply(ast::continue_statement const &)
|
||||
{}
|
||||
|
||||
void apply(ast::function_definition const & node)
|
||||
{
|
||||
compile_function_visitor{{}, {}, mcontext, lcontext}.do_apply(node);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ mut { return bp::make_mut(ctx.location); }
|
|||
if { return bp::make_if(ctx.location); }
|
||||
else { return bp::make_else(ctx.location); }
|
||||
while { return bp::make_while(ctx.location); }
|
||||
break { return bp::make_break(ctx.location); }
|
||||
continue { return bp::make_continue(ctx.location); }
|
||||
as { return bp::make_as(ctx.location); }
|
||||
func { return bp::make_func(ctx.location); }
|
||||
foreign { return bp::make_foreign(ctx.location); }
|
||||
|
|
|
|||
|
|
@ -140,6 +140,8 @@ template <typename T>
|
|||
%token if
|
||||
%token else
|
||||
%token while
|
||||
%token break
|
||||
%token continue
|
||||
%token as
|
||||
%token func
|
||||
%token foreign
|
||||
|
|
@ -247,6 +249,8 @@ statement
|
|||
| else colon { $$ = ast::else_block{@$}; }
|
||||
| else if expression colon { $$ = ast::else_if_block{std::make_unique<ast::expression>($3), @$}; }
|
||||
| while expression colon { $$ = ast::while_block{std::make_unique<ast::expression>($2), {}, @$, @$}; }
|
||||
| break { $$ = ast::break_statement{@$}; }
|
||||
| continue { $$ = ast::continue_statement{@$}; }
|
||||
| func name lparen function_declaration_argument_list rparen function_return_type colon { $$ = ast::function_definition{{$2, $4, $6, @$}, {}}; }
|
||||
| foreign func name lparen function_declaration_argument_list rparen function_return_type { $$ = ast::foreign_function_declaration{{$3, $5, $7, @$}}; }
|
||||
| return expression { $$ = ast::return_statement{std::make_unique<ast::expression>($2), @$}; }
|
||||
|
|
|
|||
|
|
@ -51,6 +51,16 @@ namespace pslang::parser
|
|||
return node.location = ast::merge(node.prelude_location, apply(*node.statements));
|
||||
}
|
||||
|
||||
ast::location apply(ast::break_statement & node)
|
||||
{
|
||||
return node.location;
|
||||
}
|
||||
|
||||
ast::location apply(ast::continue_statement & node)
|
||||
{
|
||||
return node.location;
|
||||
}
|
||||
|
||||
ast::location apply(ast::function_definition & node)
|
||||
{
|
||||
return node.location = ast::merge(node.prelude_location, apply(*node.statements));
|
||||
|
|
@ -103,6 +113,7 @@ namespace pslang::parser
|
|||
stack.push_back(result.get());
|
||||
std::size_t current_indent = 0;
|
||||
std::vector<ast::function_definition *> function_stack;
|
||||
std::vector<ast::statement_list *> loop_stack;
|
||||
|
||||
auto current_statement_list = [&](ast::location const & location) -> ast::statement_list *
|
||||
{
|
||||
|
|
@ -139,6 +150,8 @@ namespace pslang::parser
|
|||
throw ast::invalid_ast_error("Unexpected empty indent stack", ast::get_location(*statement.statement));
|
||||
if (!function_stack.empty() && std::holds_alternative<ast::statement_list *>(stack.back()) && function_stack.back()->statements.get() == std::get<ast::statement_list *>(stack.back()))
|
||||
function_stack.pop_back();
|
||||
if (!loop_stack.empty() && std::holds_alternative<ast::statement_list *>(stack.back()) && loop_stack.back() == std::get<ast::statement_list *>(stack.back()))
|
||||
loop_stack.pop_back();
|
||||
stack.pop_back();
|
||||
--current_indent;
|
||||
}
|
||||
|
|
@ -182,6 +195,7 @@ namespace pslang::parser
|
|||
while_block->statements = std::make_unique<ast::statement_list>();
|
||||
list = while_block->statements.get();
|
||||
current_statement_list(location)->statements.push_back(std::make_unique<ast::statement>(std::move(*while_block)));
|
||||
loop_stack.push_back(list);
|
||||
}
|
||||
else if (auto function_definition = std::get_if<ast::function_definition>(statement.statement.get()))
|
||||
{
|
||||
|
|
@ -229,6 +243,18 @@ namespace pslang::parser
|
|||
{
|
||||
current_statement_list(location)->statements.push_back(std::make_unique<ast::statement>(std::move(*foreign_function_declaration)));
|
||||
}
|
||||
else if (auto break_statement = std::get_if<ast::break_statement>(statement.statement.get()))
|
||||
{
|
||||
if (loop_stack.empty())
|
||||
throw parse_error("Break without an enclosing loop", break_statement->location);
|
||||
current_statement_list(location)->statements.push_back(std::make_unique<ast::statement>(std::move(*break_statement)));
|
||||
}
|
||||
else if (auto continue_statement = std::get_if<ast::continue_statement>(statement.statement.get()))
|
||||
{
|
||||
if (loop_stack.empty())
|
||||
throw parse_error("Continue without an enclosing loop", continue_statement->location);
|
||||
current_statement_list(location)->statements.push_back(std::make_unique<ast::statement>(std::move(*continue_statement)));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ast::invalid_ast_error(std::format("Unknown pre-statement \"{}\"", std::visit([](auto const & statement){ return typeid(statement).name(); }, *statement.statement)), location);
|
||||
|
|
|
|||
5
spec.txt
5
spec.txt
|
|
@ -148,8 +148,11 @@ Flow control:
|
|||
|
||||
while condition:
|
||||
statements
|
||||
if x:
|
||||
break
|
||||
if y:
|
||||
continue
|
||||
|
||||
TODO: break/continue?
|
||||
TODO: for loops? iterator/range interface?
|
||||
|
||||
======== STRUCTS ========
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue