private VarOrCallChain CompileVarOrCallChain(VarOrCallChainSyntax varOrCallChain) { var variableOrCallSyntaxes = varOrCallChain.variableOrCallSyntaxes; var state = VarOrCallChainCompileState.Start; Type typeForStaticAccess = null; var variableOrCalls = new List <VarOrCall>(); foreach (var variableOrCallSyntax in variableOrCallSyntaxes) { switch (state) { case VarOrCallChainCompileState.Start: { // The first can either be a variable, a function or a type used to call a static method or to access a static variable // TODO local variables, function args, instance args or function either static or not typeForStaticAccess = typeResolver.TryResolveTypeByTokenValue(variableOrCallSyntax.identifierToken); if (typeForStaticAccess != null) { // TODO Test this case if (variableOrCallSyntax.argumentExpressionSyntaxes != null) { throw new CompilerException($"{typeForStaticAccess.name} is a type and can't be invoked as a function", variableOrCallSyntax.identifierToken); } // Ok go on, the next will be a static method or field state = VarOrCallChainCompileState.TypeForStaticAccess; break; } var identifier = FindIdentifierOrNull(variableOrCallSyntax.identifierToken); if (identifier != null) { if (variableOrCallSyntax.argumentExpressionSyntaxes != null) { // TODO Test this case if (identifier.GetType() != typeof(Function)) { throw new CompilerException($"{identifier.Name} is not a function", variableOrCallSyntax.identifierToken); } // TODO Validate argument number and type agains function signature // TODO Test callability: if the current function is static, it can't call non-static functions! // Evaluate the args var argExprs = new List <IExpression>(); foreach (var arg in variableOrCallSyntax.argumentExpressionSyntaxes) { argExprs.Add(CompileExpression(arg)); } variableOrCalls.Add(new VarOrCall(identifier, argExprs)); state = VarOrCallChainCompileState.CallDone; } else { // TODO Test this case if ((identifier.GetType() != typeof(DeclarationStatement)) && (identifier.GetType() != typeof(FunctionArg))) { throw new CompilerException($"{identifier.Name} is not a variable", variableOrCallSyntax.identifierToken); } variableOrCalls.Add(new VarOrCall(identifier, null)); state = VarOrCallChainCompileState.AccessDone; } break; } throw new CompilerException($"Could not resolve {variableOrCallSyntax.identifierToken.value}", variableOrCallSyntax.identifierToken); } case VarOrCallChainCompileState.TypeForStaticAccess: { if (variableOrCallSyntax.argumentExpressionSyntaxes != null) { // It's a call, find the method var functionName = variableOrCallSyntax.identifierToken.value; var fun = typeForStaticAccess.GetFunctionByName(functionName); if (fun == null) { throw new CompilerException($"Type {typeForStaticAccess.name} has no function named '{functionName}'", variableOrCallSyntax.identifierToken); } // TODO Validate argument number and type agains function signature // TODO Test callability: if the current function is static, it can't call non-static functions! // Evaluate the args var argExprs = new List <IExpression>(); foreach (var arg in variableOrCallSyntax.argumentExpressionSyntaxes) { argExprs.Add(CompileExpression(arg)); } variableOrCalls.Add(new VarOrCall(fun, argExprs)); state = VarOrCallChainCompileState.CallDone; } else { throw new CompilerException($"TODO Static field access not implemented"); } } break; default: throw new CompilerException($"Invalid statement compiler state: {state}"); } } // Check final state switch (state) { // TODO Test the following error cases case VarOrCallChainCompileState.Start: throw new CompilerException($"Empty statement"); case VarOrCallChainCompileState.TypeForStaticAccess: throw new CompilerException($"Member access expected"); case VarOrCallChainCompileState.CallDone: // The statemend ended with a call, it's valid. return(new VarOrCallChain(variableOrCalls)); case VarOrCallChainCompileState.AccessDone: // The statement ended with a varible access, an assign is expected to form a valid statement return(new VarOrCallChain(variableOrCalls)); default: throw new CompilerException($"Invalid statement compiler final state: {state}"); } }
public VarOrCallChainMaybeAssignStatementSyntax(VarOrCallChainSyntax varOrCallChainSyntax, IExpressionSyntax valueToAssignExpression) { this.varOrCallChainSyntax = varOrCallChainSyntax; this.valueToAssignExpression = valueToAssignExpression; }