Browse Source

WIP: add for loops

c_for-loops
Garrit Franke 10 months ago
parent
commit
6c7e171071
  1. 73
      src/generator/c.rs
  2. 15
      src/generator/js.rs
  3. 7
      src/parser/infer.rs

73
src/generator/c.rs

@ -55,13 +55,13 @@ pub(super) fn generate_type(t: Either<Variable, Option<Type>>) -> 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<Variable, Option<Type>>) -> 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<Statement>, scope: Vec<Variable>) -> String {
fn generate_block(block: Statement, prepend: Option<String>) -> 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 += &pre;
}
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
}

15
src/generator/js.rs

@ -63,7 +63,6 @@ fn generate_block(block: Statement, prepend: Option<String>) -> String {
generated += &pre;
}
// 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>) -> 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<Expression>) -> String {
fn generate_declare(var: Variable, val: Option<Expression>) -> 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),
}
}

7
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");
}
}
_ => {}
}
}

Loading…
Cancel
Save