Skip to content

Conversation

VictorFontesCavalcante
Copy link
Contributor

Had to refactor the Environment hashmap to accommodate functions definitions. Some evals, execs and tests had to also be refactored to satisfy the new hashmap.

@rbonifacio
Copy link
Contributor

@VictorFontesCavalcante , could you please rebase from the main branch? Thanks for such a comprehensive contribution.


if items.len() < 1 {
return Err(String::from(
"List initialization must have at least one element",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since I was not in class when this decision was possibly made, I have to ask: was it explicitly decided that we can't initialise an empty list?

#[derive(Debug, Clone, PartialEq)]
pub enum EnvValue {
CInt(i32),
CReal(f32),
Copy link
Collaborator

Choose a reason for hiding this comment

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

For consistency with (most) other languages and standards, maybe this can be called CFloat ,CFloating or something like that? If we are to be strict, floating point numbers are not real numbers, as real numbers have infinite precision.

Ok(EvalResult::CReal(lhs + rhs as f32))
}
(EvalResult::CInt(lhs), EvalResult::Bool(rhs)) => {
Ok(EvalResult::CInt(lhs + rhs as i32))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Was it an explicit agreement to coerce bool to i32 in our language? I am aware that JavaScript will coerce the boolean value to an integer, and that bool is a subclass of int in Python, but do we want that in our language? I'm just asking because this may have implications for the type checker down the line.

let new_env = env.clone();
let end_value = eval(exp2, &new_env)?;

let mut srt_value = eval(&Expression::CInt(0), &new_env)?;
Copy link
Collaborator

Choose a reason for hiding this comment

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

what's the meaning of srt_value? A starting one? I am not sure I follow

new_env.insert(*name.clone(), EnvValue::None);
}
}
Ok(new_env)
Copy link
Collaborator

Choose a reason for hiding this comment

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

doesn't something like the following (I have not compiled/run, so there may be mistakes in my reasoning) look simpler/more concise?

Statement::Assignment(name, exp) => {
        let value = eval(exp, &env)?;
        let mut new_env = env;

        // Directly insert the value after cloning the name
        new_env.insert(name.clone(), match value {
            EvalResult::CInt(val) => EnvValue::CInt(val),
            EvalResult::CReal(val) => EnvValue::CReal(val),
            EvalResult::Bool(val) => EnvValue::Bool(val),
            EvalResult::List(val) => EnvValue::List(val),
            EvalResult::None => EnvValue::None,
        });

        Ok(new_env)
    }
    ```

EvalResult::List(vec) => {
for item in vec {
match item {
EvalResult::CInt(v) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

similar question to previous comment

@helpmehelpus
Copy link
Collaborator

Very interesting (and good) work! I have some concerns, however, in terms of code comprehension:

In the interpreter code, we seem to have completely forfeited a layered approach in favour of doing everything in each arm of the matches. I wonder whether using some helper functions, like coerce_to_int, coerce_to_real, or other code that is repeated throughout, so that we maitain some sense of modularity and preserve readability. I left a few questions regarding language design/types just so we are all on the same page about these decisions; I am likely asking stuff that has been already decided upon during the classes, so I just want to be sure I am on par.

In (the unlikely) case you need help rebasing:

git remote add upstream git@github.com:UnBCIC-TP2/r-python.git

git remote -v should now display your fork as origin, and the main repo as upstream.

git fetch upstream
git checkout <your-branch>
git rebase upstream/main

You may have to resolve some conflicts at this stage before continuing. To push to your origin, do

git push origin <your-branch> --force

For future reference: When making changes to core data structures/types/functionality of projects, it is nice to add a detailed description in the Pull Request explaining your main choices. You may want to preempt reviewers' questions, which in this case could be like:

  • Why do EnvValue needs changing, and why do we have to introduce EvalResult
  • What is the plan for functions like add, eval_binary_arith_op and so on? Will they just become unused/deprecated? If so, are we planning to remove them from the code?
  • Is it strictly necessary to have to clone them, or can we pass them around as references (probably irrelevant to our project, but just one more example).

Congratulations for the contribution!!

EmersonJr pushed a commit to EmersonJr/r-python that referenced this pull request Feb 20, 2025
add test for only one function at modtest
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.

3 participants