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 LocalVariableTable for output to support debug #44

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

warmthdawn
Copy link

As title, write local variable table to the compile output in order to support debug.
(The debug is provided by a vscode plugin I'm developing)
https://github.com/warmthdawn/zs-debug-adapter

Copy link
Contributor

@kindlich kindlich left a comment

Choose a reason for hiding this comment

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

Some questions:

  • This Repository is for ZenScript1, so the version that 1.7.10 up to 1.12 use, that is intended?
  • IIRC, in ZenCode, we put this information as part of the MethodOutput object, and have methodOutput.end() write automatically (so it can't be forgotten for some method types). Any reason to put it in the scope here?

Possible Edge cases

  • Nested scopes that don't belong together (e.g. local variables inside a lambda shouldn't be added to the outer variable table)
  • Variable Capturing in Lambdas
  • Naming object0 this for instance methods in zenClasses vs. static methods where object0 is the first parameter
  • Names of Temp variables that some converters introduce (e.g. the List->Array caster that also converts elements)
  • Variables Captured within Lambdas

Other things to keep in mind:

  • Currently the legacy builds of CraftTweaker might go against a different Commit than the master commit of this repo: e714482. When testing, make sure to properly update the ZenScript repo for your CrT stuff.
    https://github.com/CraftTweaker/CraftTweaker/tree/legacy
    Also, Make sure you have an old enough version of gradle running for that project 😛

If you want to discuss more, I'd suggest you join our discord server

public class LocalVariableTable {

private final IEnvironmentClass envClass;
private final LinkedList<List<LocalVariable>> scopeStack = new LinkedList<>();
Copy link
Contributor

Choose a reason for hiding this comment

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

IF the outer list is only ever used as Stack, define it as such

private final Stack<List<...>> .. = new LinkedList<>();

Copy link
Author

Choose a reason for hiding this comment

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

Yes, the outer is only ever used as stack, however Stack is not a superclass of LinkedList. 😛

Comment on lines +24 to +29
public void beginScope() {
scopeStack.push(new ArrayList<>());
}


public void endScope(Label end) {
Copy link
Contributor

Choose a reason for hiding this comment

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

How would this work for nested scopes that have nothing to do with each other?
E.g.

function myFunc() as int {
    val someLambda as function()int = function() {
        val x = 10;
        return x;
    }

    return someLambda();
}

Copy link
Author

Choose a reason for hiding this comment

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

Well, the 'scope' I defined here is for cases of block expression, scopes like lambda creates a new stackframe thus has no impact on owner's local variable tables, even if it has a capture variable, it is provided separately without affecting the local variable.

actually this is just a trick to have access of the end label prop for local variable.

Comment on lines +80 to +83
if(firstLabel == null) {
firstLabel = label;
}
lastLabel = label;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why these instead of setting firstLabel in start() and lastLabel in end()?

Comment on lines +1075 to +1078
if(firstLabel == null) {
firstLabel = label;
}
lastLabel = label;
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this now became a bit more duplicated code you could delegate to label?

posision(pos) {
    Label label = new Label
    this.label(label);
    visitor.visitLineNumber(...);
}

Copy link
Author

Choose a reason for hiding this comment

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

Yes, the first label would be initialized later when the first expression compiles.

.map(ZenType::toASMType)
.map(Type::getDescriptor)
.toArray(String[]::new);
final String[] arguments = environmentMethod.getCapturedVariables().stream().map(SymbolCaptured::getEvaluated).peek(expression -> expression.compile(true, environment)).map(Expression::getType).map(ZenType::toASMType).map(Type::getDescriptor).toArray(String[]::new);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why the reformat instead of keeping it chopped?

Copy link
Author

Choose a reason for hiding this comment

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

Sorry, this is just a mistake because i forge to sync code style to ide at first and forge to rollback some changes. I'll settle that later

.map(ZenType::toASMType)
.map(Type::getDescriptor)
.toArray(String[]::new);
final String[] arguments = environmentMethod.getCapturedVariables().stream().map(SymbolCaptured::getEvaluated).peek(expression -> expression.compile(true, environment)).map(Expression::getType).map(ZenType::toASMType).map(Type::getDescriptor).toArray(String[]::new);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why the reformat instead of keeping it chopped down?

return isStatic
? members.get(name).instance(position, environment)
: members.get(name).instance(position, environment, value);
return isStatic ? members.get(name).instance(position, environment) : members.get(name).instance(position, environment, value);
Copy link
Contributor

Choose a reason for hiding this comment

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

The the reformat instead of keeping it chopped down?

Comment on lines +61 to +63
if (!create) {
return -1;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Default value vs. Exception/Error?

Copy link
Author

Choose a reason for hiding this comment

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

o, right,error here would be better

@warmthdawn
Copy link
Author

As for why I didn't write the final output in end(), first of all, there are some methods (such as lambda-generated temporary methods) that don't need these. Second, the generation needs to get something related to Environment, and it seems too much for MethodOutput.

this pr is intended to mc1.12, BTW, for zencode, since it wirtes the 'end' immediately next to start label, i wonder whether there are any problems.

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.

2 participants