Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions AresScript.Tests/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,31 @@ public Task SyntaxErrors_AreThrown()
return Task.CompletedTask;
}

[Test]
public async Task Validation_AllowsMemberAccess_OnUnknownFunctionParameter()
{
var script = """
def meme(bepis):
bepis.GetTemperature()
""";

await ValidateScriptAsync(script);
}

[Test]
public async Task Validation_AssignsVariable_FromUserFunctionCall()
{
var script = """
def main():
return 1

bepis = main()
assert bepis == 1
""";

await ValidateScriptAsync(script);
}

[Test]
public async Task Range_OneArg_GeneratesCorrectSequence()
{
Expand Down
35 changes: 32 additions & 3 deletions AresScript/Interpreters/AresValidationInterpreter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public override async Task VisitFuncBlock(AresLangParser.FuncBlockContext contex
{
foreach(var parameter in _pendingFunctionParameters.Peek())
{
_environment.AssignVariable(parameter, AresValueHelper.CreateNull());
_environment.AssignVariable(parameter, CreateUnknownValue());
}
}

Expand Down Expand Up @@ -461,7 +461,7 @@ public override async Task VisitLambdaExpr(AresLangParser.LambdaExprContext cont
{
foreach(var parameter in parameterNames)
{
_environment.AssignVariable(parameter, AresValueHelper.CreateNull());
_environment.AssignVariable(parameter, CreateUnknownValue());
}

await Visit(body);
Expand Down Expand Up @@ -495,6 +495,7 @@ public override Task VisitMemberAccess([NotNull] AresLangParser.MemberAccessCont
{
var ctxExpr = context.expression();
var id = context.ID().GetText();
var receiverSchema = _typeInference.Visit(ctxExpr);
if(!TryResolveValue(ctxExpr, out var value))
{
throw new AresInterpreterException(
Expand All @@ -513,6 +514,11 @@ public override Task VisitMemberAccess([NotNull] AresLangParser.MemberAccessCont
);
}

if(receiverSchema.Type is AresDataType.Any or AresDataType.UnspecifiedType)
{
return Task.CompletedTask;
}

if(value.KindCase == AresValue.KindOneofCase.StructValue)
{
if(value.StructValue.Fields.ContainsKey(id))
Expand All @@ -533,6 +539,12 @@ public override Task VisitMemberAccess([NotNull] AresLangParser.MemberAccessCont
);
}

private static AresValue CreateUnknownValue()
{
// A value with no active oneof kind maps to UnspecifiedType in schema inference.
return new AresValue();
}

public override async Task VisitFunctionCall(AresLangParser.FunctionCallContext ctx)
{
var ctxExpr = ctx.expression();
Expand Down Expand Up @@ -1028,12 +1040,29 @@ private static int FindParameterIndex(IReadOnlyList<string> parameters, string n
case AresLangParser.FunctionCallContext functionCallContext:
{
var funcId = TryResolveFunctionId(functionCallContext.expression());
if(funcId is not null && _environment.TryGetSystemFunction(funcId, out var systemFunction))
if(funcId is null)
{
break;
}

if(_environment.TryGetValue(funcId, out var aliasValue) && aliasValue.FunctionValue is not null)
{
funcId = aliasValue.FunctionValue.FunctionId;
}

if(_environment.TryGetSystemFunction(funcId, out var systemFunction))
{
var schema = systemFunction.OutputSchema;
var dummyValue = InterpreterHelpers.CreateDummyValue(schema);
return dummyValue;
}

if(_environment.TryGetUserFunction(funcId, out var _) || _environment.TryGetUserLambda(funcId, out var _))
{
// We cannot know user-function return shape statically in this pass, but assignment target
// should still be introduced into scope for subsequent validation.
return CreateUnknownValue();
}
break;
}
}
Expand Down
19 changes: 17 additions & 2 deletions UI/Components/ScriptEditor.razor
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<StandaloneCodeEditor CssClass="h-100" @ref="_editor" Id="ares-editor" ConstructionOptions="EditorConstructionOptions" />

@code {
private const string DefaultScript = "# Welcome to ARES\ndef main():\n return True\n";
private StandaloneCodeEditor _editor;

private IJSObjectReference? _setupModule;
Expand All @@ -30,8 +31,21 @@
[Parameter]
public IMonacoHoverProvider? HoverProvider { get; set; }

[Parameter]
public string? InitialScript { get; set; }

public Task<string> GetScript() => _editor.GetValue();

public async Task SetScript(string script)
{
if(_editor is null)
{
return;
}

await _editor.SetValue(script ?? string.Empty);
}

protected override async Task OnAfterRenderAsync(bool firstRender)
{
if(firstRender)
Expand Down Expand Up @@ -129,13 +143,14 @@

private StandaloneEditorConstructionOptions EditorConstructionOptions(StandaloneCodeEditor editor)
{
var initialScript = string.IsNullOrWhiteSpace(InitialScript) ? DefaultScript : InitialScript;

return new StandaloneEditorConstructionOptions
{
Language = "ares",
AutomaticLayout = true,
SemanticHighlightingEnabled = true,
Value = "# Welcome to ARES\ndef main():\n return True\n"
Value = initialScript
};
}
}

Loading