-
Notifications
You must be signed in to change notification settings - Fork 22
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
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this 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<>(); |
There was a problem hiding this comment.
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<>();
There was a problem hiding this comment.
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. 😛
public void beginScope() { | ||
scopeStack.push(new ArrayList<>()); | ||
} | ||
|
||
|
||
public void endScope(Label end) { |
There was a problem hiding this comment.
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();
}
There was a problem hiding this comment.
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.
if(firstLabel == null) { | ||
firstLabel = label; | ||
} | ||
lastLabel = label; |
There was a problem hiding this comment.
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()
?
if(firstLabel == null) { | ||
firstLabel = label; | ||
} | ||
lastLabel = label; |
There was a problem hiding this comment.
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(...);
}
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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?
if (!create) { | ||
return -1; | ||
} |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
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. |
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