Skip to content
This repository has been archived by the owner on Jan 22, 2022. It is now read-only.

Commit

Permalink
Various bug fixes and better error reporting
Browse files Browse the repository at this point in the history
- Allow use of empty statements
- Allow use of '+' operator as an identity operation
- Update not supported exception to reflect the current support for jagged arrays, but not multidimensional arrays
- Allow empty conditions in `for` loops
- Prevent compile from continuing on errors while building class definitions
- Handle more cases where someone attempts to access undefined names and fix some cases where the name would not be propagated correctly for the error message
  • Loading branch information
MerlinVR committed Apr 13, 2020
1 parent 754b59b commit 06a70d3
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 33 deletions.
31 changes: 23 additions & 8 deletions Assets/UdonSharp/Editor/UdonSharpASTVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,11 @@ public override void VisitUsingDirective(UsingDirectiveSyntax node)
}
}

public override void VisitEmptyStatement(EmptyStatementSyntax node)
{
UpdateSyntaxNode(node);
}

public override void VisitBlock(BlockSyntax node)
{
UpdateSyntaxNode(node);
Expand Down Expand Up @@ -564,7 +569,7 @@ public override void VisitElementAccessExpression(ElementAccessExpressionSyntax
Visit(node.Expression);

if (node.ArgumentList.Arguments.Count != 1)
throw new System.NotSupportedException("UdonSharp does not support multidimensional or jagged array accesses yet");
throw new System.NotSupportedException("UdonSharp does not support multidimensional accesses yet");

SymbolDefinition indexerSymbol = null;

Expand Down Expand Up @@ -1051,6 +1056,13 @@ public override void VisitPrefixUnaryExpression(PrefixUnaryExpressionSyntax node
{
Visit(node.Operand);

if (node.OperatorToken.Kind() == SyntaxKind.PlusToken || node.OperatorToken.Kind() == SyntaxKind.UnaryPlusExpression)
{
if (topScope != null)
topScope.SetToLocalSymbol(operandCapture.ExecuteGet());
return;
}

List<MethodInfo> operatorMethods = new List<MethodInfo>();

switch (node.OperatorToken.Kind())
Expand Down Expand Up @@ -2006,15 +2018,18 @@ public override void VisitForStatement(ForStatementSyntax node)

JumpLabel forLoopEnd = visitorContext.labelTable.GetNewJumpLabel("forLoopEnd");

SymbolDefinition conditionSymbol = null;
using (ExpressionCaptureScope conditionScope = new ExpressionCaptureScope(visitorContext, null))
if (node.Condition != null)
{
Visit(node.Condition);
conditionSymbol = HandleImplicitBoolCast(conditionScope.ExecuteGet());
}
SymbolDefinition conditionSymbol = null;
using (ExpressionCaptureScope conditionScope = new ExpressionCaptureScope(visitorContext, null))
{
Visit(node.Condition);
conditionSymbol = HandleImplicitBoolCast(conditionScope.ExecuteGet());
}

visitorContext.uasmBuilder.AddPush(conditionSymbol);
visitorContext.uasmBuilder.AddJumpIfFalse(forLoopEnd);
visitorContext.uasmBuilder.AddPush(conditionSymbol);
visitorContext.uasmBuilder.AddJumpIfFalse(forLoopEnd);
}

visitorContext.continueLabelStack.Push(forLoopContinue);
visitorContext.breakLabelStack.Push(forLoopEnd);
Expand Down
35 changes: 19 additions & 16 deletions Assets/UdonSharp/Editor/UdonSharpCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,27 +48,30 @@ public void Compile()
if (classDefinitions == null)
totalErrorCount++;

foreach (CompilationModule module in modules)
{
EditorUtility.DisplayProgressBar("UdonSharp Compile",
$"Compiling {AssetDatabase.GetAssetPath(module.programAsset.sourceCsScript)}...",
Mathf.Clamp01((moduleCounter++ / (float)modules.Length) + Random.Range(0.01f, 1f / modules.Length))); // Make it look like we're doing work :D

int moduleErrorCount = module.Compile(classDefinitions);
totalErrorCount += moduleErrorCount;
}

if (totalErrorCount == 0)
{
EditorUtility.DisplayProgressBar("UdonSharp Compile", "Assigning constants...", 1f);
int initializerErrorCount = AssignHeapConstants();
totalErrorCount += initializerErrorCount;
foreach (CompilationModule module in modules)
{
EditorUtility.DisplayProgressBar("UdonSharp Compile",
$"Compiling {AssetDatabase.GetAssetPath(module.programAsset.sourceCsScript)}...",
Mathf.Clamp01((moduleCounter++ / (float)modules.Length) + Random.Range(0.01f, 1f / modules.Length))); // Make it look like we're doing work :D

if (initializerErrorCount == 0)
int moduleErrorCount = module.Compile(classDefinitions);
totalErrorCount += moduleErrorCount;
}

if (totalErrorCount == 0)
{
foreach (CompilationModule module in modules)
EditorUtility.DisplayProgressBar("UdonSharp Compile", "Assigning constants...", 1f);
int initializerErrorCount = AssignHeapConstants();
totalErrorCount += initializerErrorCount;

if (initializerErrorCount == 0)
{
module.programAsset.ApplyProgram();
foreach (CompilationModule module in modules)
{
module.programAsset.ApplyProgram();
}
}
}
}
Expand Down
31 changes: 22 additions & 9 deletions Assets/UdonSharp/Editor/UdonSharpExpressionCapture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public ExpressionCaptureScope(ASTVisitorContext context, ExpressionCaptureScope
public void Dispose()
{
if (parentScope != null)
parentScope.InheretScope(this);
parentScope.InheritScope(this);

Debug.Assert(visitorContext.topCaptureScope == this);
if (visitorContext.topCaptureScope == this)
Expand All @@ -115,10 +115,9 @@ public void Dispose()
disposed = true;
}

private void InheretScope(ExpressionCaptureScope childScope)
private void InheritScope(ExpressionCaptureScope childScope)
{
if (captureArchetype != ExpressionCaptureArchetype.Unknown ||
childScope.captureArchetype == ExpressionCaptureArchetype.Unknown ||
childScope.captureArchetype == ExpressionCaptureArchetype.This ||
childScope.captureArchetype == ExpressionCaptureArchetype.Method ||
childScope.captureArchetype == ExpressionCaptureArchetype.Namespace)
Expand All @@ -136,6 +135,17 @@ private void InheretScope(ExpressionCaptureScope childScope)
captureExternUserField = childScope.captureExternUserField;
captureExternUserMethod = childScope.captureExternUserMethod;
InternalMethodHandler = childScope.InternalMethodHandler;
unresolvedAccessChain = childScope.unresolvedAccessChain;
}

private void CheckScopeValidity()
{
if (IsUnknownArchetype())
{
string[] unresolvedTokens = unresolvedAccessChain.Split('.');
string invalidName = unresolvedTokens.Length > 1 ? unresolvedTokens[unresolvedTokens.Length - 2] : unresolvedTokens[0];
throw new System.Exception($"The name '{invalidName}' does not exist in the current context");
}
}

public void SetToLocalSymbol(SymbolDefinition symbol)
Expand Down Expand Up @@ -292,6 +302,8 @@ public SymbolDefinition ExecuteGet()
return captureLocalSymbol;

SymbolDefinition outSymbol = null;

CheckScopeValidity();

if (captureArchetype == ExpressionCaptureArchetype.Property)
{
Expand Down Expand Up @@ -376,12 +388,6 @@ public SymbolDefinition ExecuteGet()
// Capture type should still be valid from the last transition
outSymbol = visitorContext.topTable.CreateConstSymbol(captureType, GetEnumValue());
}
else if (captureArchetype == ExpressionCaptureArchetype.Unknown)
{
string[] unresolvedTokens = unresolvedAccessChain.Split('.');
string invalidName = unresolvedTokens.Length > 1 ? unresolvedTokens[unresolvedTokens.Length - 2] : unresolvedTokens[0];
throw new System.Exception($"The name '{invalidName}' does not exist in the current context");
}
else
{
throw new System.Exception("Get can only be run on Fields, Properties, Local Symbols, array indexers, and the `this` keyword");
Expand All @@ -392,6 +398,8 @@ public SymbolDefinition ExecuteGet()

public void ExecuteSet(SymbolDefinition value, bool explicitCast = false)
{
CheckScopeValidity();

SymbolDefinition convertedValue = CastSymbolToType(value, GetReturnType(true), explicitCast);

// If it's a local symbol, it's just a simple COPY
Expand Down Expand Up @@ -472,6 +480,8 @@ public void ExecuteSet(SymbolDefinition value, bool explicitCast = false)
// Just a stub for now that will be extended to avoid the COPY instruction when possible
public void ExecuteSetDirect(ExpressionCaptureScope valueExpression, bool explicitCast = false)
{
CheckScopeValidity();

ExecuteSet(valueExpression.ExecuteGet(), explicitCast);
}

Expand Down Expand Up @@ -1354,12 +1364,15 @@ public SymbolDefinition Invoke(SymbolDefinition[] invokeParams)
}
else
{
CheckScopeValidity();
throw new System.Exception($"Cannot call invoke on archetype {captureArchetype}");
}
}

public System.Type GetReturnType(bool getUserType = false)
{
CheckScopeValidity();

if (captureArchetype == ExpressionCaptureArchetype.Method)
throw new System.Exception("Cannot infer return type from method without function arguments");

Expand Down

0 comments on commit 06a70d3

Please sign in to comment.