Skip to content

Commit 248c7aa

Browse files
committed
feat: integrate stdlib IO with expression calls and complete type checking for new constructs + demo .rpy file
1 parent 0b038de commit 248c7aa

File tree

8 files changed

+261
-7
lines changed

8 files changed

+261
-7
lines changed

examples/hello_io.rpy

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
var _ = print("Hello from R-Python");
2+
var _ = print("2 + 3 = ");
3+
var resultado = 2 + 3;
4+
var _ = print(resultado);

src/interpreter/expression_eval.rs

Lines changed: 121 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::statement_execute::Computation;
22
use crate::environment::environment::Environment;
3-
use crate::ir::ast::{Expression, Name};
3+
use crate::ir::ast::{Expression, Name, Statement};
4+
use crate::stdlib::standard_library::get_metabuiltins_table;
45

56
#[derive(Debug, PartialEq, Clone)]
67
pub enum ExpressionResult {
@@ -422,7 +423,125 @@ pub fn eval_function_call(
422423
Err(e) => Err(e),
423424
}
424425
}
425-
_ => Err(format!("Function {} not found", name)),
426+
None => {
427+
// Se não for função definida pelo usuário, tenta despachar para a stdlib
428+
let table = get_metabuiltins_table();
429+
if let Some(meta_fn) = table.get(&name) {
430+
let mut meta_env: Environment<Expression> = Environment::new();
431+
432+
match name.as_str() {
433+
// input([prompt]) -> String
434+
"input" => {
435+
if let Some(prompt_expr) = args.get(0) {
436+
let prompt_val = match eval(prompt_expr.clone(), env)? {
437+
ExpressionResult::Value(Expression::CString(s)) => {
438+
Expression::CString(s)
439+
}
440+
ExpressionResult::Value(v) => {
441+
// Fallback simples: usa Debug para montar string
442+
Expression::CString(format!("{:?}", v))
443+
}
444+
ExpressionResult::Propagate(e) => {
445+
return Ok(ExpressionResult::Propagate(e))
446+
}
447+
};
448+
meta_env.map_variable("prompt".to_string(), false, prompt_val);
449+
}
450+
451+
let stmt = meta_fn(&mut meta_env);
452+
if let Statement::Return(expr) = stmt {
453+
Ok(ExpressionResult::Value(*expr))
454+
} else {
455+
Err("[Runtime Error] input builtin did not return a value".into())
456+
}
457+
}
458+
459+
// print(value) -> Unit, com efeito em stdout
460+
"print" => {
461+
if args.len() != 1 {
462+
return Err("[Runtime Error] print expects exactly 1 argument".into());
463+
}
464+
let val = match eval(args[0].clone(), env)? {
465+
ExpressionResult::Value(v) => v,
466+
ExpressionResult::Propagate(e) => {
467+
return Ok(ExpressionResult::Propagate(e))
468+
}
469+
};
470+
meta_env.map_variable("value".to_string(), false, val);
471+
let _ = meta_fn(&mut meta_env);
472+
Ok(ExpressionResult::Value(Expression::CVoid))
473+
}
474+
475+
// open(path, [mode], [content]) -> String ou Unit
476+
"open" => {
477+
if args.is_empty() {
478+
return Err(
479+
"[Runtime Error] open expects at least 1 argument (path)".into()
480+
);
481+
}
482+
483+
// path
484+
let path_val = match eval(args[0].clone(), env)? {
485+
ExpressionResult::Value(Expression::CString(s)) => {
486+
Expression::CString(s)
487+
}
488+
ExpressionResult::Value(_) => {
489+
return Err("[Runtime Error] open path must be a string".into());
490+
}
491+
ExpressionResult::Propagate(e) => {
492+
return Ok(ExpressionResult::Propagate(e))
493+
}
494+
};
495+
meta_env.map_variable("path".to_string(), false, path_val);
496+
497+
// mode (opcional)
498+
if args.len() >= 2 {
499+
let mode_val = match eval(args[1].clone(), env)? {
500+
ExpressionResult::Value(Expression::CString(s)) => {
501+
Expression::CString(s)
502+
}
503+
ExpressionResult::Value(_) => {
504+
return Err("[Runtime Error] open mode must be a string".into());
505+
}
506+
ExpressionResult::Propagate(e) => {
507+
return Ok(ExpressionResult::Propagate(e))
508+
}
509+
};
510+
meta_env.map_variable("mode".to_string(), false, mode_val);
511+
}
512+
513+
// content (opcional, para 'w' / 'a')
514+
if args.len() >= 3 {
515+
let content_val = match eval(args[2].clone(), env)? {
516+
ExpressionResult::Value(Expression::CString(s)) => {
517+
Expression::CString(s)
518+
}
519+
ExpressionResult::Value(_) => {
520+
return Err(
521+
"[Runtime Error] open content must be a string".into()
522+
);
523+
}
524+
ExpressionResult::Propagate(e) => {
525+
return Ok(ExpressionResult::Propagate(e))
526+
}
527+
};
528+
meta_env.map_variable("content".to_string(), false, content_val);
529+
}
530+
531+
let stmt = meta_fn(&mut meta_env);
532+
if let Statement::Return(expr) = stmt {
533+
Ok(ExpressionResult::Value(*expr))
534+
} else {
535+
Err("[Runtime Error] open builtin did not return a value".into())
536+
}
537+
}
538+
539+
_ => Err(format!("Function {} not found", name)),
540+
}
541+
} else {
542+
Err(format!("Function {} not found", name))
543+
}
544+
}
426545
}
427546
}
428547

src/interpreter/statement_execute.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,12 @@ pub fn execute(stmt: Statement, env: &Environment<Expression>) -> Result<Computa
479479
Ok(Computation::Continue(new_env))
480480
}
481481

482+
// Executa uma expressão apenas por seus efeitos colaterais (por exemplo, print(x)).
483+
Statement::ExprStmt(exp) => match eval(*exp, &new_env)? {
484+
ExpressionResult::Value(_) => Ok(Computation::Continue(new_env)),
485+
ExpressionResult::Propagate(expr) => Ok(Computation::PropagateError(expr, new_env)),
486+
},
487+
482488
Statement::MetaStmt(ref name) => {
483489
let table = get_metabuiltins_table();
484490
if let Some(f) = table.get(name) {

src/ir/ast.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,5 +152,7 @@ pub enum Statement {
152152
FuncDef(Function),
153153
Return(Box<Expression>),
154154
TypeDeclaration(Name, Vec<ValueConstructor>),
155+
/// Avalia uma expressão apenas por seus efeitos colaterais (ex: chamada de função).
156+
ExprStmt(Box<Expression>),
155157
MetaStmt(String),
156158
}

src/parser/keywords.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,4 @@ pub const KEYWORDS: &[&str] = &[
2323
"True",
2424
"False",
2525
"test",
26-
"print",
27-
"input",
28-
"open",
2926
];

src/pretty_print/pretty_statements.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,9 @@ impl ToDoc for Statement {
205205
)
206206
}
207207

208+
// Statement de expressão: apenas imprime a expressão seguida de ';'
209+
Statement::ExprStmt(expr) => concat(expr.to_doc(), text(";")),
210+
208211
// Metabuiltin statement: just emit its name as a standalone command.
209212
Statement::MetaStmt(name) => concat(text("meta "), text(name.clone())),
210213

src/type_checker/expression_type_checker.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub fn check_expr(exp: Expression, env: &Environment<Type>) -> Result<Type, Erro
1919
Expression::Or(l, r) => check_bin_boolean_expression(*l, *r, env),
2020
Expression::Not(e) => check_not_expression(*e, env),
2121
Expression::EQ(l, r) => check_bin_relational_expression(*l, *r, env),
22+
Expression::NEQ(l, r) => check_bin_relational_expression(*l, *r, env),
2223
Expression::GT(l, r) => check_bin_relational_expression(*l, *r, env),
2324
Expression::LT(l, r) => check_bin_relational_expression(*l, *r, env),
2425
Expression::GTE(l, r) => check_bin_relational_expression(*l, *r, env),
@@ -33,9 +34,46 @@ pub fn check_expr(exp: Expression, env: &Environment<Type>) -> Result<Type, Erro
3334
Expression::Unwrap(e) => check_unwrap_type(*e, env),
3435
Expression::Propagate(e) => check_propagate_type(*e, env),
3536
Expression::ListValue(elements) => check_list_value(&elements, env),
37+
Expression::Tuple(elements) => check_tuple_value(&elements, env),
38+
Expression::FuncCall(name, args) => check_function_call(name, args, env),
3639
Expression::Constructor(name, args) => check_adt_constructor(name, args, env),
40+
}
41+
}
3742

38-
_ => Err("not implemented yet.".to_string()),
43+
fn check_function_call(
44+
name: Name,
45+
args: Vec<Expression>,
46+
env: &Environment<Type>,
47+
) -> Result<Type, ErrorMessage> {
48+
match env.lookup_function(&name) {
49+
Some(function) => {
50+
// Checa número de argumentos
51+
if args.len() != function.params.len() {
52+
return Err(format!(
53+
"[Type Error] Function '{}' expects {} arguments, but got {}.",
54+
name,
55+
function.params.len(),
56+
args.len()
57+
));
58+
}
59+
60+
// Checa tipos de cada argumento contra o parâmetro correspondente
61+
for (arg_expr, param) in args.into_iter().zip(function.params.iter()) {
62+
let arg_type = check_expr(arg_expr, env)?;
63+
let param_type = param.argument_type.clone();
64+
65+
// Permite TAny em qualquer lado como curinga
66+
if param_type != Type::TAny && arg_type != Type::TAny && arg_type != param_type {
67+
return Err(format!(
68+
"[Type Error] In call to function '{}', argument '{}' expected type '{:?}', found '{:?}'.",
69+
name, param.argument_name, param_type, arg_type
70+
));
71+
}
72+
}
73+
74+
Ok(function.kind.clone())
75+
}
76+
None => Err(format!("[Type Error] Function '{}' is not defined.", name)),
3977
}
4078
}
4179

@@ -184,6 +222,18 @@ fn check_list_value(
184222
Ok(Type::TList(Box::new(first_type)))
185223
}
186224

225+
fn check_tuple_value(
226+
elements: &[Expression],
227+
env: &Environment<Type>,
228+
) -> Result<Type, ErrorMessage> {
229+
let mut types = Vec::with_capacity(elements.len());
230+
for element in elements {
231+
let element_type = check_expr(element.clone(), env)?;
232+
types.push(element_type);
233+
}
234+
Ok(Type::TTuple(types))
235+
}
236+
187237
fn check_adt_constructor(
188238
name: Name,
189239
args: Vec<Box<Expression>>,

src/type_checker/statement_type_checker.rs

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,54 @@ pub fn check_stmt(
1616
Statement::IfThenElse(cond, stmt_then, stmt_else_opt) => {
1717
check_if_then_else_stmt(cond, stmt_then, stmt_else_opt, env)
1818
}
19+
Statement::IfChain {
20+
branches,
21+
else_branch,
22+
} => check_if_chain_stmt(branches, else_branch, env),
1923
Statement::While(cond, stmt) => check_while_stmt(cond, stmt, env),
2024
Statement::For(var, expr, stmt) => check_for_stmt(var, expr, stmt, env),
2125
Statement::FuncDef(function) => check_func_def_stmt(function, env),
2226
Statement::TypeDeclaration(name, cons) => check_adt_declarations_stmt(name, cons, env),
2327
Statement::Return(exp) => check_return_stmt(exp, env),
2428

29+
// Blocos no nível de statement: empilham escopo e checam internamente.
30+
Statement::Block(stmts) => {
31+
let mut block_env = env.clone();
32+
block_env.push();
33+
34+
for s in stmts {
35+
block_env = check_stmt(s, &block_env)?;
36+
}
37+
block_env.pop();
38+
Ok(block_env)
39+
}
40+
2541
Statement::Assert(expr1, errmsg) => check_assert(expr1, errmsg, env),
2642
Statement::AssertTrue(expr1, errmsg) => check_assert_true(expr1, errmsg, env),
2743
Statement::AssertFalse(expr1, errmsg) => check_assert_false(expr1, errmsg, env),
2844
Statement::AssertEQ(lhs, rhs, errmsg) => check_assert_eq(lhs, rhs, errmsg, env),
2945
Statement::AssertNEQ(lhs, rhs, errmsg) => check_assert_neq(lhs, rhs, errmsg, env),
3046
Statement::TestDef(function) => check_test_function_stmt(function, env),
3147

32-
_ => Err("Not implemented yet".to_string()),
48+
// Statement de expressão: só garante que a expressão é bem-tipada.
49+
Statement::ExprStmt(exp) => {
50+
let _ = check_expr(*exp, env)?;
51+
Ok(env.clone())
52+
}
53+
54+
// Metabuiltins são tratados apenas em tempo de execução; do ponto de vista
55+
// de tipos, não alteram o ambiente.
56+
Statement::MetaStmt(_) => Ok(env.clone()),
57+
58+
// AssertFails carrega apenas uma mensagem literal; não há expressão a checar.
59+
Statement::AssertFails(_) => Ok(env.clone()),
60+
61+
// ModTestDef agrupa um statement de teste por módulo; checamos o corpo,
62+
// mas não expomos nada novo no ambiente global.
63+
Statement::ModTestDef(_, stmt) => {
64+
let _ = check_stmt(*stmt, env)?;
65+
Ok(env.clone())
66+
}
3367
}
3468
}
3569

@@ -152,6 +186,45 @@ fn check_if_then_else_stmt(
152186
Ok(new_env)
153187
}
154188

189+
fn check_if_chain_stmt(
190+
branches: Vec<(Box<Expression>, Box<Statement>)>,
191+
else_branch: Option<Box<Statement>>,
192+
env: &Environment<Type>,
193+
) -> Result<Environment<Type>, ErrorMessage> {
194+
if branches.is_empty() {
195+
return Err("[Type Error] if-chain must have at least one branch.".to_string());
196+
}
197+
198+
let mut branch_envs: Vec<Environment<Type>> = Vec::new();
199+
200+
for (cond, stmt) in branches {
201+
let mut local_env = env.clone();
202+
let cond_type = check_expr(*cond, &local_env)?;
203+
if cond_type != Type::TBool {
204+
return Err(
205+
"[Type Error] a condition in an 'if/elif' branch must be of type boolean."
206+
.to_string(),
207+
);
208+
}
209+
local_env = check_stmt(*stmt, &local_env)?;
210+
branch_envs.push(local_env);
211+
}
212+
213+
if let Some(stmt) = else_branch {
214+
let else_env = check_stmt(*stmt, env)?;
215+
branch_envs.push(else_env);
216+
}
217+
218+
// Mescla progressivamente todos os ambientes resultantes,
219+
// começando do ambiente original.
220+
let mut acc_env = env.clone();
221+
for branch_env in branch_envs {
222+
acc_env = merge_environments(&acc_env, &branch_env)?;
223+
}
224+
225+
Ok(acc_env)
226+
}
227+
155228
fn check_while_stmt(
156229
cond: Box<Expression>,
157230
stmt: Box<Statement>,

0 commit comments

Comments
 (0)