Ejemplo n.º 1
0
        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}");
            }
        }
Ejemplo n.º 2
0
 public VarOrCallChainMaybeAssignStatementSyntax(VarOrCallChainSyntax varOrCallChainSyntax, IExpressionSyntax valueToAssignExpression)
 {
     this.varOrCallChainSyntax    = varOrCallChainSyntax;
     this.valueToAssignExpression = valueToAssignExpression;
 }