Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add native map traversing functionality #106

Merged
merged 15 commits into from
May 3, 2024

Conversation

Gusarich
Copy link
Member

@Gusarich Gusarich commented Dec 1, 2023

This PR introduces the for loop - currently just the map traversing version of it, but I'm also thinking about implementing general purpose for loops in future.

Syntax (may be changed, it's up for discussions):

for (k, v in m) {
    // k: key, v: value, m: map
}

What have been already done:

  • grammar
  • ast definitions
  • statement resolving

What have to be done:

  • actual implementation of map traversing loop
  • tests

@Gusarich
Copy link
Member Author

Gusarich commented Dec 1, 2023

I've ran into a little problem when was trying to implement it. Here's an example of how to traverse a map in FunC:

(int key, slice val, int flag) = d.udict_get_min?(256);
while (flag) {
    ;; do something with pair key->val
    
    (key, val, flag) = d.udict_get_next?(256, key);
}

This loop uses 3 variables: key, value and flag that indicates whether the loop should be terminated or not (actually it's set to false when there are no more keys in map).
We can easily define key and value variables by using same names in the FunC code (id(keyName) etc), but I'm not sure about the best solution regarding the flag variable. It must not be overlapped with any other existing variable names including other flag variables in case with nested loops.

Well, we can just ban nested map traversing loops... but I don't think it's a good idea.

@anton-trunov what do you think?

@xsr

This comment was marked as abuse.

@Gusarich
Copy link
Member Author

Gusarich commented Dec 4, 2023

«just generate random name like for_flag_RANDOM_HASH

@xsr I've thought about this, but it adds some kind of indeterminacy to compiler which isn't good.

@nonam3e
Copy link
Contributor

nonam3e commented Dec 16, 2023

I've ran into a little problem when was trying to implement it. Here's an example of how to traverse a map in FunC:

(int key, slice val, int flag) = d.udict_get_min?(256);
while (flag) {
    ;; do something with pair key->val
    
    (key, val, flag) = d.udict_get_next?(256, key);
}

This loop uses 3 variables: key, value and flag that indicates whether the loop should be terminated or not (actually it's set to false when there are no more keys in map).
We can easily define key and value variables by using same names in the FunC code (id(keyName) etc), but I'm not sure about the best solution regarding the flag variable. It must not be overlapped with any other existing variable names including other flag variables in case with nested loops.

Well, we can just ban nested map traversing loops... but I don't think it's a good idea.

@anton-trunov what do you think?

Maybe can it be solved by checking key instead of flag (key.is_null?)?

@Gusarich
Copy link
Member Author

Maybe can it be solved by checking key instead of flag (key.is_null?)?

@nonam3e Well, it’ll work, but will consume more gas (18 for each iteration).

@anton-trunov anton-trunov added the kind: language feature Intent to add a language feature label Feb 15, 2024
@anton-trunov anton-trunov linked an issue Feb 15, 2024 that may be closed by this pull request
@anton-trunov anton-trunov added this to the v1.3.0 milestone Feb 16, 2024
@anton-trunov anton-trunov self-assigned this Feb 16, 2024
@anton-trunov anton-trunov added the feature: maps The map datatype and operations on it label Mar 5, 2024
@novusnota
Copy link
Member

Found an interesting read on designing a for-each loop syntax: https://harelang.org/blog/2024-04-01-introducing-for-each-loops-in-hare. This won't help much with this issue, but it can be somewhat inspirational nonetheless, despite coming from a systems programming language :)

@anton-trunov
Copy link
Member

We can easily define key and value variables by using same names in the FunC code (id(keyName) etc), but I'm not sure about the best solution regarding the flag variable. It must not be overlapped with any other existing variable names including other flag variables in case with nested loops.

@Gusarich The usual approach here is to define a fresh identifier generator. Something like this:

// fresh.ts

let counter = 0;    // a mutable variable

function freshIdentifier(prefix: string): string {
    const fresh = `__tact_freshId${prefix}${counter}`;
    counter += 1;
    return fresh;
}

and then you can use it to generate fresh flag variables with freshIdentifier("flag"). Using a prefix is not necessary, it should make debugging a bit easier.

@novusnota novusnota mentioned this pull request Apr 25, 2024
16 tasks
src/test/features/map-traverse.tact Show resolved Hide resolved
tact.config.json Show resolved Hide resolved
@Gusarich Gusarich marked this pull request as ready for review May 3, 2024 09:04
@Gusarich Gusarich requested a review from anton-trunov May 3, 2024 09:04
anton-trunov
anton-trunov previously approved these changes May 3, 2024
Copy link
Member

@anton-trunov anton-trunov left a comment

Choose a reason for hiding this comment

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

HUGE!

WORKS ON MY macOS MACHINE
@anton-trunov anton-trunov merged commit 19fec50 into tact-lang:main May 3, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature: maps The map datatype and operations on it kind: language feature Intent to add a language feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support loop for map
5 participants