From 6c7e1710710174b64db7ee3cd6d5eb0c70d666fc Mon Sep 17 00:00:00 2001 From: Garrit Franke Date: Mon, 8 Feb 2021 22:03:42 +0100 Subject: [PATCH] WIP: add for loops --- src/generator/c.rs | 73 +++++++++++++++++++++++++++++++++++++-------- src/generator/js.rs | 15 ++++++---- src/parser/infer.rs | 7 +++++ 3 files changed, 76 insertions(+), 19 deletions(-) diff --git a/src/generator/c.rs b/src/generator/c.rs index 5b7a9b9..ef124ce 100644 --- a/src/generator/c.rs +++ b/src/generator/c.rs @@ -55,13 +55,13 @@ pub(super) fn generate_type(t: Either>) -> String { Type::Str => "char *".into(), Type::Any => "void *".into(), Type::Bool => "bool".into(), - Type::Array(_) => match name { + Type::Array(arr_ty) => match name { Some(n) => format!( "{T} {N}[]", - T = generate_type(Either::Right(Some(t))), + T = generate_type(Either::Right(Some(*arr_ty))), N = n ), - None => format!("{}[]", generate_type(Either::Right(Some(t)))), + None => format!("{}[]", generate_type(Either::Right(Some(*arr_ty)))), }, }, None => "void".into(), @@ -71,9 +71,7 @@ pub(super) fn generate_type(t: Either>) -> String { fn generate_function(func: Function) -> String { let mut buf = String::new(); buf += &format!("{} ", &generate_function_signature(func.clone())); - if let Statement::Block(statements, scope) = func.body { - buf += &generate_block(statements, scope); - } + buf += &generate_block(func.body, None); buf } @@ -89,10 +87,20 @@ fn generate_function_signature(func: Function) -> String { format!("{T} {N}({A})", T = t, N = func.name, A = arguments) } -fn generate_block(block: Vec, scope: Vec) -> String { +fn generate_block(block: Statement, prepend: Option) -> String { let mut generated = String::from("{\n"); - for statement in block { + let statements = match block { + Statement::Block(statements, _) => statements, + _ => panic!("Statement passed to generate_block was not a block"), + }; + + // Prepend statements + if let Some(pre) = prepend { + generated += ⪯ + } + + for statement in statements { generated += &generate_statement(statement); } @@ -110,9 +118,9 @@ fn generate_statement(statement: Statement) -> String { generate_conditional(expr, *if_state, else_state.map(|x| *x)) } Statement::Assign(name, state) => generate_assign(*name, *state), - Statement::Block(statements, scope) => generate_block(statements, scope), + Statement::Block(_, _) => generate_block(statement, None), Statement::While(expr, body) => generate_while_loop(expr, *body), - Statement::For(ident, expr, body) => todo!(), + Statement::For(ident, expr, body) => generate_for_loop(ident, expr, *body), Statement::Continue => todo!(), Statement::Break => todo!(), }; @@ -140,9 +148,48 @@ fn generate_while_loop(expr: Expression, body: Statement) -> String { out_str += &generate_expression(expr); out_str += ") "; - if let Statement::Block(statements, scope) = body { - out_str += &generate_block(statements, scope); - } + out_str += &generate_block(body, None); + out_str +} + +fn generate_for_loop(ident: Variable, expr: Expression, body: Statement) -> String { + // Assign expression to variable to access it from within the loop + let expr_name = format!("loop_orig_{}", ident.name); + let expr_var = Variable { + name: expr_name.clone(), + ty: ident.ty.clone(), + }; + let mut out_str = format!("{};\n", generate_declare(expr_var, Some(expr))); + + // Allocate size of array + out_str += &format!("int size = sizeof {E} / sizeof {E}[0];", E = expr_name); + + // Loop signature + out_str += &format!( + "for ({T} iter_{I} = 0; iter_{I} < size; iter_{I}++)", + T = generate_type(Either::Right(ident.ty.clone())), + I = ident.name, + ); + + let prepended_statement = match ident.ty { + Some(Type::Array(_)) => format!( + // In arrays, the type contains the name, so it must be omitted + "{T} = {E}[iter_{I}];\n", + T = generate_type(Either::Right(ident.ty)), + I = ident.name, + E = expr_name + ), + _ => format!( + "{T} {I} = {E}[iter_{I}];\n", + T = generate_type(Either::Right(ident.ty)), + I = ident.name, + E = expr_name + ), + }; + + // Block with prepended declaration of the actual variable + // TODO: Use generate_declare here + out_str += &generate_block(body, Some(prepended_statement)); out_str } diff --git a/src/generator/js.rs b/src/generator/js.rs index 8649982..ad6cc8d 100644 --- a/src/generator/js.rs +++ b/src/generator/js.rs @@ -63,7 +63,6 @@ fn generate_block(block: Statement, prepend: Option) -> String { generated += ⪯ } - // TODO: Prepend statements let statements = match block { Statement::Block(blk, _) => blk, _ => panic!("Block body should be of type Statement::Block"), @@ -81,7 +80,7 @@ fn generate_block(block: Statement, prepend: Option) -> String { fn generate_statement(statement: Statement) -> String { let state = match statement { Statement::Return(ret) => generate_return(ret), - Statement::Declare(name, val) => generate_declare(name.name, val), + Statement::Declare(name, val) => generate_declare(name, val), Statement::Exp(val) => generate_expression(val), Statement::If(expr, if_state, else_state) => { generate_conditional(expr, *if_state, else_state.map(|x| *x)) @@ -121,7 +120,11 @@ fn generate_while_loop(expr: Expression, body: Statement) -> String { fn generate_for_loop(ident: Variable, expr: Expression, body: Statement) -> String { // Assign expression to variable to access it from within the loop let expr_name = format!("loop_orig_{}", ident.name); - let mut out_str = format!("{};\n", generate_declare(expr_name.clone(), Some(expr))); + let expr_var = Variable { + name: expr_name.clone(), + ty: ident.ty, + }; + let mut out_str = format!("{};\n", generate_declare(expr_var, Some(expr))); // Loop signature out_str += &format!( @@ -194,12 +197,12 @@ fn generate_conditional( outcome } -fn generate_declare(name: String, val: Option) -> String { +fn generate_declare(var: Variable, val: Option) -> String { // var is used here to not collide with scopes. // TODO: Can let be used instead? match val { - Some(expr) => format!("var {} = {}", name, generate_expression(expr)), - None => format!("var {}", name), + Some(expr) => format!("var {} = {}", var.name, generate_expression(expr)), + None => format!("var {}", var.name), } } diff --git a/src/parser/infer.rs b/src/parser/infer.rs index f64ca3e..6048487 100644 --- a/src/parser/infer.rs +++ b/src/parser/infer.rs @@ -22,6 +22,13 @@ pub(super) fn infer(program: &mut Program) -> Result<(), String> { } } } + Statement::For(var, _, _) => { + #[cfg(feature = "backend_c")] + if let None = &var.ty { + // TODO: Evaluate type based on expression + todo!("Please explicitly specify the type in for loops"); + } + } _ => {} } }