Skip to content

Project 5 — Second Milestone#10

Open
SapoSopa wants to merge 21 commits into
rbonifacio:mainfrom
SapoSopa:feat/milestone-2-pr
Open

Project 5 — Second Milestone#10
SapoSopa wants to merge 21 commits into
rbonifacio:mainfrom
SapoSopa:feat/milestone-2-pr

Conversation

@SapoSopa

@SapoSopa SapoSopa commented Jun 8, 2026

Copy link
Copy Markdown

##Grupo:

  • Álvaro Cavalcante Negromonte
  • Gabriel Valença Mayerhofer
  • Henrique César Higino Holanda Cordeiro
  • João Victor Nascimento Lima
  • Vinicius de Souza Rodrigues

Resumo

Este PR organiza a base da Milestone 2 do Projeto 5, formalizando a semântica de funções de primeira classe e closures, e adicionando testes-esqueleto mais completos para a divisão de trabalho do grupo.

O que mudou

Objetivo

Deixar explícito o contrato entre type checker e interpreter.

SapoSopa and others added 21 commits April 13, 2026 21:47
[TypeChecker] Check lambda and function-value calls
[FEATURE]: Add closure snapshot capture for lexical environment restoration
Copilot AI review requested due to automatic review settings June 8, 2026 01:03

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR adds first-class function values to MiniC, including lambda expressions, function-typed variables, and closure capture semantics in the interpreter/type-checker.

Changes:

  • Extend the parser/AST to support fn(...) -> T { ... } lambdas and calling arbitrary expressions (not just named functions).
  • Update the type checker to type lambdas, validate calls through function values, and allow fn(...) -> ... f; declarations.
  • Update the interpreter runtime to represent and invoke closures with captured environments; add extensive test coverage and supporting docs.

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/ir/ast.rs Adds Expr::Lambda / Expr::CallExpr and makes declaration initializers optional.
src/parser/expressions.rs Parses lambda expressions and general call syntax callee(args).
src/parser/functions.rs Adds parsing for function types fn(Ts...) -> Ret.
src/parser/statements.rs Allows declarations without initializers (Type ident;).
src/parser/identifiers.rs Reserves fn as a keyword.
src/semantic/type_checker.rs Types lambdas, function-value calls, and function-typed decls without init.
src/interpreter/value.rs Adds a Closure runtime representation with captured environment.
src/interpreter/exec_stmt.rs Handles Decl without initializer at runtime.
src/interpreter/eval_expr.rs Evaluates lambdas to closures and supports calling function values.
tests/* Adds new parser/type-check/integration/runtime tests for function types, lambdas, and closures.
docs/semantics-first-class-fn.md Documents intended closure semantics and function-value behavior.
docs/09-projects.md Updates project assignment table and milestone date text.
Comments suppressed due to low confidence (1)

src/interpreter/eval_expr.rs:1

  • eval_expr now supports calling function values via eval_call_value(...), but eval_call(...) is still limited to env.get_function(name) and doesn’t delegate to the new logic. Since statement-level calls (Statement::Call) still go through eval_call, calling a function stored in a variable (e.g. fn(int)->int f; f = ...; f(1);) will not work consistently. Make eval_call fetch the callee from the same value environment as Expr::Call does (e.g., env.get(name).cloned()) and then delegate to eval_call_value(callee, args, env, Some(name)), so both statement calls and expression calls share the same behavior.
//! Expression evaluator for the MiniC interpreter.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/ir/ast.rs
Comment on lines +107 to +123
/// Chamada de função por expressão: chmd(args)
/// apenas para não mexer em Call, mas depois podemos mesclar os dois (Call pode ser um caso especial de CallExpr onde callee é um Ident).
/// Ex.: 'f(42)', '(funçãolambda)(42)', etc.)
CallExpr {
chmd: Box<ExprD<Ty>>,
args: Vec<ExprD<Ty>>,
},

/// Função Lambda: `fn(params) -> return_tipo { crp }`
/// regra pra não ficar ambiguo:
/// 'fn(...) -> ...' é tipo, ou seja 'Type::Fun'
/// 'fn(...) -> ... { ... }' é expressão, ou seja 'Expr::Lambda'
Lambda {
params: Vec<Param>,
return_tipo: Type,
crp: Box<StatementD<Ty>>,
},
Comment on lines +331 to +374
fn type_of_function_call(
callee_ty: &Type,
args: &[CheckedExpr],
label: &str,
) -> Result<Type, TypeError> {
match callee_ty {
Type::Fun(param_tys, return_ty) => {
if args.len() != param_tys.len() {
return Err(TypeError::new(format!(
"{} expects {} arguments, got {}",
label,
param_tys.len(),
args.len()
)));
}

for (i, (arg, param_ty)) in args.iter().zip(param_tys.iter()).enumerate() {
if !types_compatible(&arg.ty, param_ty) {
return Err(TypeError::new(format!(
"argument {} to {}: expected {:?}, got {:?}",
i + 1,
label,
param_ty,
arg.ty
)));
}
}

Ok((**return_ty).clone())
}

other => {
if label == "function value" {
Err(TypeError::new("attempting to call a non-function value"))
}
else {
Err(TypeError::new(format!(
"{} is not a function, got {:?}",
label, other
)))
}
}
}
}
Comment on lines +52 to +53
Decisão sobre declarações sem inicializador
- Não declarar uma variável de tipo função sem init (a não ser que queiram mais trabalho, ai só avisar no grupo pra gente rever isso).
Comment on lines +694 to +706
(Type::Fun(params_a, ret_a), Type::Fun(params_b, ret_b)) => {
if params_a.len() != params_b.len() {
return false;
}

for (a, b) in params_a.iter().zip(params_b.iter()) {
if a != b {
return false;
}
}

ret_a == ret_b
},
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants