コード例 #1
0
        public int Execute(Frame frame)
        {
            object result = frame.result;

            if (to.IsAssignableFrom(result))
            {
                return(1);
            }

            RedwoodType type;

            if (result is RedwoodObject rwo)
            {
                type = rwo.Type;
            }
            else
            {
                type = RedwoodType.GetForCSharpType(result.GetType());
            }

            // TODO: this may be repeating existing work that occurs later
            if (!type.HasImplicitConversion(to))
            {
                throw new NotImplementedException();
            }

            Lambda conversion = RuntimeUtil.GetConversionLambda(type, to);

            frame.result = conversion.Run(frame.result);
            return(1);
        }
コード例 #2
0
        internal override IEnumerable <Instruction> Compile()
        {
            IEnumerable <Instruction> compiledCondition = Condition.Compile();

            Instruction[] compiledPathTrue      = PathTrue.Compile().ToArray();
            Instruction[] compiledElseStatement = ElseStatement?.Compile().ToArray() ?? new Instruction[0];

            List <Instruction> instructions = new List <Instruction>();

            instructions.AddRange(compiledCondition);
            if (RedwoodType.GetForCSharpType(typeof(bool)) != Condition.GetKnownType())
            {
                throw new NotImplementedException();
            }

            // The index of the jump instruction relative to the the else is -1
            // (ie. right before the start). When we factor in the jump, we need
            // to skip 2 additional instructions
            instructions.Add(new ConditionalJumpInstruction(compiledElseStatement.Length + 2));
            instructions.AddRange(compiledElseStatement);
            instructions.Add(new JumpInstruction(compiledPathTrue.Length + 1));
            instructions.AddRange(compiledPathTrue);

            return(instructions);
        }
コード例 #3
0
        public void CanReturnSimpleValue()
        {
            Lambda lambda = Compiler.CompileFunction(
                new FunctionDefinition
            {
                ClassMethod = false,
                Name        = "testFunc",
                ReturnType  = new TypeSyntax
                {
                    TypeName = new NameExpression
                    {
                        Name = "string"
                    }
                },
                Parameters = new ParameterDefinition[] { },
                Body       = new BlockStatement
                {
                    Statements = new Statement[]
                    {
                        new ReturnStatement
                        {
                            Expression = new StringConstant {
                                Value = "Test"
                            }
                        }
                    }
                }
            }
                );

            Assert.Equal(RedwoodType.GetForCSharpType(typeof(string)), lambda.ReturnType);
            Assert.Equal("Test", lambda.Run());
        }
コード例 #4
0
        internal override void Bind(Binder binder)
        {
            Chain.Bind(binder);
            RedwoodType chainType = Chain.GetKnownType();

            if (chainType == null)
            {
                return;
            }

            if (chainType.CSharpType == null)
            {
                KnownType = chainType.slotTypes?[chainType.slotMap[Element.Name]];
            }
            else
            {
                PropertyInfo property;
                FieldInfo    field;
                MemberResolver.TryResolveMember(chainType, Element.Name, false, out property, out field);
                if (property != null)
                {
                    KnownType = RedwoodType.GetForCSharpType(property.PropertyType);
                }
                if (field != null)
                {
                    KnownType = RedwoodType.GetForCSharpType(field.FieldType);
                }
            }
        }
コード例 #5
0
        public override RedwoodType GetKnownType()
        {
            switch (Operator)
            {
            case BinaryOperator.LogicalAnd:
            case BinaryOperator.LogicalOr:
                return(RedwoodType.GetForCSharpType(typeof(bool)));

            case BinaryOperator.As:
                return(Right.EvaluateConstant() as RedwoodType);    // TODO!

            default:
                break;
            }

            if (LambdaType == null || LambdaType.CSharpType == typeof(LambdaGroup))
            {
                return(null);
            }

            RedwoodType[] signature = LambdaType.GenericArguments;
            if (signature == null || signature.Length == 0)
            {
                return(null);
            }

            return(signature[signature.Length - 1]);
        }
コード例 #6
0
 public override RedwoodType GetKnownType()
 {
     if (Value < int.MaxValue && Value > int.MinValue)
     {
         return(RedwoodType.GetForCSharpType(typeof(int)));
     }
     return(RedwoodType.GetForCSharpType(typeof(BigInteger)));
 }
コード例 #7
0
 private void Init(object target, MethodBase info)
 {
     boundTarget = target;
     this.info   = info;
     ParameterInfo[] parameters   = info.GetParameters();
     RedwoodType[]   expectedArgs = new RedwoodType[parameters.Length];
     for (int i = 0; i < parameters.Length; i++)
     {
         expectedArgs[i] = RedwoodType.GetForCSharpType(parameters[i].ParameterType);
     }
     ExpectedArgs = expectedArgs;
 }
コード例 #8
0
        private IEnumerable <Instruction> CompileLogicalExpression()
        {
            List <Instruction> instructions = new List <Instruction>();

            instructions.AddRange(Left.Compile());
            if (Left.GetKnownType() != RedwoodType.GetForCSharpType(typeof(bool)))
            {
                instructions.AddRange(
                    Compiler.CompileImplicitConversion(
                        Left.GetKnownType(),
                        RedwoodType.GetForCSharpType(typeof(bool))
                        )
                    );
            }

            List <Instruction> rightInstructions = new List <Instruction>();

            rightInstructions.AddRange(Right.Compile());
            if (Right.GetKnownType() != RedwoodType.GetForCSharpType(typeof(bool)))
            {
                instructions.AddRange(
                    Compiler.CompileImplicitConversion(
                        Right.GetKnownType(),
                        RedwoodType.GetForCSharpType(typeof(bool))
                        )
                    );
            }

            // Short circuiting
            switch (Operator)
            {
            case BinaryOperator.LogicalAnd:
                // If we get a true, then don't skip the second condition
                instructions.Add(new ConditionalJumpInstruction(2));
                instructions.Add(new JumpInstruction(rightInstructions.Count + 1));
                break;

            case BinaryOperator.LogicalOr:
                instructions.Add(new ConditionalJumpInstruction(rightInstructions.Count + 1));
                break;

            default:
                // Should not happen
                throw new NotImplementedException();
            }

            instructions.AddRange(rightInstructions);
            return(instructions);
        }
コード例 #9
0
        private static List <Variable> GetSpecialMappedVariables()
        {
            List <Variable> builtinVariables = new List <Variable>();

            foreach (string name in RedwoodType.specialMappedTypes.Keys)
            {
                builtinVariables.Add(new Variable
                {
                    Name            = name,
                    DefinedConstant = true,
                    ConstantValue   = RedwoodType.specialMappedTypes[name],
                    KnownType       = RedwoodType.GetForCSharpType(typeof(RedwoodType))
                });
            }
            return(builtinVariables);
        }
コード例 #10
0
        public async Task FunctionCanHoldClosureInformation()
        {
            string code = @"
function<string> testFunc()
{
    let string varA = ""Test123"";
    function<string> innerTestFunc()
    {
        return varA;
    }
    return innerTestFunc();
}";

            Lambda lambda = await MakeLambda(code);

            Assert.Equal(RedwoodType.GetForCSharpType(typeof(string)), lambda.ReturnType);
            Assert.Equal("Test123", lambda.Run());
        }
コード例 #11
0
        public async Task FunctionCanBeParsedAndCalled()
        {
            string code = @"
function<string> testFunc()
{
    function<string> innerTestFunc(string paramA)
    {
        return paramA;
    }
    return innerTestFunc(""Test"");
}";


            Lambda lambda = await MakeLambda(code);

            Assert.Equal(RedwoodType.GetForCSharpType(typeof(string)), lambda.ReturnType);
            Assert.Equal("Test", lambda.Run());
        }
コード例 #12
0
ファイル: ForStatement.cs プロジェクト: gfmcknight/Redwood
        internal override IEnumerable <Instruction> Compile()
        {
            List <Instruction> instructions = new List <Instruction>();

            instructions.AddRange(Initializer?.Compile() ?? new Instruction[0]);

            List <Instruction> bodyInstructions = Body.Compile().ToList();

            bodyInstructions.AddRange(Incrementor?.Compile() ?? new Instruction[0]);



            List <Instruction> check;

            if (Condition == null)
            {
                // No condition? We're in a forever loop
                check = new List <Instruction>();
            }
            else
            {
                check = Condition.Compile().ToList();
                check.AddRange(
                    Compiler.CompileImplicitConversion(
                        Condition.GetKnownType(),
                        RedwoodType.GetForCSharpType(typeof(bool))
                        )
                    );
                check.Add(new ConditionalJumpInstruction(2));
                // Next instruction (1) + Body + Increment + Jump instruction (1)
                check.Add(new JumpInstruction(bodyInstructions.Count + 2));
            }

            // Jump back to the beginning of the loop
            bodyInstructions.Add(new JumpInstruction(-(bodyInstructions.Count + check.Count)));

            instructions.AddRange(check);
            instructions.AddRange(bodyInstructions);
            return(instructions);
        }
コード例 #13
0
        internal override IEnumerable <NameExpression> Walk()
        {
            base.Walk();
            string typename = CollectName(namespaceWalk);

            if (TryGetTypeFromAssemblies(typename, out Type cSharpType))
            {
                DeclaredVariable.DefinedConstant = true;
                DeclaredVariable.KnownType       = RedwoodType.GetForCSharpType(typeof(RedwoodType));
                DeclaredVariable.ConstantValue   = RedwoodType.GetForCSharpType(cSharpType);
            }
            else
            {
                FreeVar = new NameExpression {
                    Name = typename
                };
                // Let the compiler take it because it needs to go parse
                // these additional modules
                return(new NameExpression[] { FreeVar });
            }
            return(new NameExpression[0]);
        }
コード例 #14
0
        internal static List <OverloadGroup> GenerateOverloads(
            List <FunctionDefinition> functions)
        {
            Dictionary <string, List <FunctionDefinition> > functionsByName =
                new Dictionary <string, List <FunctionDefinition> >();

            foreach (FunctionDefinition function in functions)
            {
                if (functionsByName.ContainsKey(function.Name))
                {
                    functionsByName[function.Name].Add(function);
                }
                else
                {
                    functionsByName.Add(function.Name, new List <FunctionDefinition>(
                                            new FunctionDefinition[] { function })
                                        );
                }
            }

            // TODO: Define a strict ordering for functions in an overload group
            List <OverloadGroup> overloads = new List <OverloadGroup>();

            foreach (List <FunctionDefinition> overload in functionsByName.Values)
            {
                Variable variable = overload.Count == 1 ?
                                    overload[0].DeclaredVariable :
                                    new Variable
                {
                    Name      = overload[0].Name,
                    KnownType = RedwoodType.GetForCSharpType(typeof(LambdaGroup))
                };
                overloads.Add(new OverloadGroup(overload, variable));
            }
            return(overloads);
        }
コード例 #15
0
        private InternalLambdaDescription CompileInterfaceConversion(RedwoodType type)
        {
            int closureId = This.ClosureID;

            int[] slots = RuntimeUtil.GetSlotMapsToInterface(Type, type);
            List <Instruction> instructions = new List <Instruction>();

            for (int i = 0; i < slots.Length; i++)
            {
                // Get the member on our class
                instructions.Add(new LookupClosureInstruction(closureId, slots[i]));
                // Assign it as an argument for the closure
                instructions.Add(new AssignLocalInstruction(i));
            }

            if (type.CSharpType != null)
            {
                instructions.Add(
                    new BuildArrayInstruction(
                        Enumerable
                        .Range(0, slots.Length)
                        .ToArray(),
                        typeof(object)
                        )
                    );
                // Save it right past the arguments for the creation of
                // the array
                instructions.Add(new AssignLocalInstruction(slots.Length));
            }

            instructions.Add(new LoadConstantInstruction(type));
            instructions.Add(new LookupExternalMemberLambdaInstruction(
                                 "Constructor",
                                 RedwoodType.GetForCSharpType(typeof(RedwoodType))
                                 ));

            if (type.CSharpType == null)
            {
                // We already arranged all of the arguments in order
                instructions.Add(
                    new InternalCallInstruction(
                        Enumerable
                        .Range(0, slots.Length)
                        .ToArray()
                        )
                    );
            }
            else
            {
                instructions.Add(
                    new ExternalCallInstruction(
                        new int[] { slots.Length }
                        )
                    );
            }


            instructions.Add(new ReturnInstruction());

            return(new InternalLambdaDescription
            {
                argTypes = new RedwoodType[0],
                closureSize = 0,
                stackSize = slots.Length + 1,
                returnType = type,
                instructions = instructions.ToArray()
            });
        }
コード例 #16
0
 internal ExternalLambda(object target, MethodInfo info)
 {
     Init(target, info);
     ReturnType = RedwoodType.GetForCSharpType(info.ReturnType);
 }
コード例 #17
0
        internal override IEnumerable <NameExpression> Walk()
        {
            Type = RedwoodType.Make(this);
            base.Walk();
            DeclaredVariable.KnownType       = RedwoodType.GetForCSharpType(typeof(RedwoodType));
            DeclaredVariable.DefinedConstant = true;
            DeclaredVariable.ConstantValue   = Type;
            List <NameExpression> freeVars     = new List <NameExpression>();
            List <Variable>       declaredVars = new List <Variable>();

            InterfaceImplicitConversionVars = new List <Variable>();
            int maxConstructorArgs = 0;

            This = new Variable
            {
                Name      = "this",
                KnownType = Type
            };
            declaredVars.Add(This);

            if (ParameterFields != null)
            {
                maxConstructorArgs = ParameterFields.Length;
                foreach (ParameterDefinition param in ParameterFields)
                {
                    freeVars.AddRange(param.Walk());
                    declaredVars.Add(param.DeclaredVariable);
                }
            }

            foreach (TypeSyntax interfaceType in Interfaces)
            {
                freeVars.AddRange(interfaceType.Walk());
                // TODO: What if we inherit an implicit, or if we
                // a function that is meant to represent this, or
                // an implicit declared function?
                InterfaceImplicitConversionVars.Add(
                    new Variable
                {
                    Name            = RuntimeUtil.GetNameOfConversionToType(interfaceType.TypeName.Name),
                    Closured        = true,
                    DefinedConstant = true
                }
                    );
            }

            foreach (LetDefinition field in InstanceFields)
            {
                freeVars.AddRange(field.Walk());
                declaredVars.Add(field.DeclaredVariable);
            }

            foreach (FunctionDefinition constructor in Constructors)
            {
                freeVars.AddRange(constructor.Walk());
                maxConstructorArgs = Math.Max(maxConstructorArgs, constructor.Parameters.Length);
            }

            TempArgumentVariables = new List <Variable>();
            for (int i = 0; i < maxConstructorArgs; i++)
            {
                TempArgumentVariables.Add(new Variable
                {
                    Temporary = true
                });
            }

            foreach (FunctionDefinition method in Methods)
            {
                freeVars.AddRange(method.Walk());
                // Closure these variables even though they aren't in the
                // object's map so that they can be directly accessed
                method.DeclaredVariable.Closured = true;
            }
            Overloads = Compiler.GenerateOverloads(Methods.ToList());
            declaredVars.AddRange(Overloads.Select(o => o.variable));

            declaredVars.AddRange(InterfaceImplicitConversionVars);
            MemberVariables = declaredVars;
            // Make sure that all of our variables end up in the closure that
            // makes up our RedwoodObject
            foreach (Variable member in declaredVars)
            {
                member.Closured = true;
            }

            // Treat the class as a closure that can be populated and then
            // updated by all methods.
            Compiler.MatchVariables(freeVars, declaredVars);

            // When it comes to static methods, we don't want to match to
            // our own instance variables.
            foreach (FunctionDefinition method in StaticMethods)
            {
                freeVars.AddRange(method.Walk());
            }
            StaticOverloads = Compiler.GenerateOverloads(StaticMethods.ToList());

            return(freeVars);
        }
コード例 #18
0
        internal override IEnumerable <NameExpression> Walk()
        {
            Type = RedwoodType.Make(this);
            base.Walk();
            DeclaredVariable.KnownType       = RedwoodType.GetForCSharpType(typeof(RedwoodType));
            DeclaredVariable.DefinedConstant = true;
            DeclaredVariable.ConstantValue   = Type;

            List <NameExpression> freeVars     = new List <NameExpression>();
            List <Variable>       declaredVars = new List <Variable>();

            // The set of variables which must be supplied when creating the interface
            List <Variable> varsSupplied = new List <Variable>();

            This = new Variable
            {
                Name      = "this",
                KnownType = null, // Dynamic since the reference isn't necessarily our own type
            };
            declaredVars.Add(This);
            varsSupplied.Add(This);

            foreach (FunctionDefinition method in Methods)
            {
                // Make sure that the method is a stub
                if (method.Body != null)
                {
                    throw new NotImplementedException();
                }

                freeVars.AddRange(method.Walk());
                // As in the ClassDefinition, these need to be closured variables
                method.DeclaredVariable.Closured = true;
                varsSupplied.Add(method.DeclaredVariable);
            }

            // For every raw function and the this variable,
            // we're going to need to take is as an argument
            // for building the interface. Each of these should
            // live on the stack as they are variables.
            ArgumentVariables = varsSupplied
                                .Select(variable =>
                                        new Variable
            {
                Name = variable.Name
            }
                                        )
                                .ToList();
            SuppliedVariables = varsSupplied;

            Overloads = Compiler.GenerateOverloads(Methods.ToList());
            declaredVars.AddRange(Overloads.Select(o => o.variable));

            foreach (Variable variable in declaredVars)
            {
                variable.Closured = true;
            }

            Variables = declaredVars;

            // There is no need to match against the fields of the class as
            // all methods are stubs, and no code is closured against the
            // interface itself.
            return(freeVars);
        }
コード例 #19
0
 public override RedwoodType GetKnownType()
 {
     return(RedwoodType.GetForCSharpType(typeof(RedwoodType)));
 }
コード例 #20
0
        internal override void Bind(Binder binder)
        {
            // We have a series of temporary variables, so we will need
            // to discard them after the call is made
            binder.Bookmark();

            // We have the process
            // Eval arg i, assign variable i, eval arg i+1, assign variable i+1
            // so if we, for instance, bind every argument, then bind every temp
            // variable, we are sure to clobber our own arguments
            for (int i = 0; i < Arguments.Length; i++)
            {
                Arguments[i].Bind(binder);
                binder.BindVariable(ArgumentVariables[i]);
            }

            binder.Checkout();

            bool fullyResolvedTypes;

            if (Callee == null)
            {
                fullyResolvedTypes = FunctionName.GetKnownType() != null;
            }
            else
            {
                fullyResolvedTypes = Callee.GetKnownType() != null;
            }

            RedwoodType[] argumentTypes = new RedwoodType[Arguments.Length];
            for (int i = 0; i < Arguments.Length; i++)
            {
                argumentTypes[i] = Arguments[i].GetKnownType();
                // Not really sure whether we care about this, but it might be useful
                // for compiling variable assignments
                ArgumentVariables[i].KnownType = argumentTypes[i];
                fullyResolvedTypes            &= argumentTypes[i] != null;
            }

            // If we have fully resolved types (ie. all argument types are known
            // and so is the callee type) we definitely know the return type
            FullyResolved = fullyResolvedTypes;
            // We have two options for determining an exact type, either:
            // 1) The method is fully resolved. One lambda type will come out of
            //    the many,
            // or
            // 2) the method is not fully resolved, but the provided arguments
            //    narrow the methods down a single option.
            if (Callee == null)
            {
                LambdaType = FunctionName.GetKnownType();
                // If we have a lambda group, we should try to resolve it
                ResolveLambdaGroupOverload(argumentTypes);
            }
            else if (Callee.GetKnownType() == null)
            {
                LambdaType = null;
            }
            else if (Callee.GetKnownType().CSharpType == null)
            {
                LambdaType = Callee
                             .GetKnownType()
                             .GetKnownTypeOfMember(FunctionName.Name);

                // Make sure that calls to class functions also have the correct
                // lambda type
                ResolveLambdaGroupOverload(argumentTypes);
            }
            else if (Callee.GetKnownType().CSharpType == typeof(RedwoodType))
            {
                if (!Callee.Constant)
                {
                    LambdaType = null;
                }
                else if (Callee.EvaluateConstant() is RedwoodType calleeType)
                {
                    if (calleeType.CSharpType == null)
                    {
                        LambdaType = calleeType
                                     .GetKnownTypeForStaticMember(FunctionName.Name);
                        ResolveLambdaGroupOverload(argumentTypes);
                    }
                    else
                    {
                        MethodInfo[] infos;
                        bool         methodExists = MemberResolver.TryResolveMethod(
                            null,
                            calleeType,
                            FunctionName.Name,
                            true,
                            out infos);

                        if (!methodExists)
                        {
                            throw new NotImplementedException();
                        }

                        BindExternal(infos);
                    }
                }
                else
                {
                    // This should never happen?
                    throw new NotImplementedException();
                }
            }
            else
            {
                MethodInfo[] infos;
                bool         methodExists = MemberResolver.TryResolveMethod(
                    null,
                    Callee.GetKnownType(),
                    FunctionName.Name,
                    false,
                    out infos);

                if (!methodExists)
                {
                    // TODO: Can an object have a lambda field?
                    throw new NotImplementedException();
                }

                BindExternal(infos);
            }

            void BindExternal(MethodInfo[] infos)
            {
                ExternalMethodGroup = new MethodGroup(infos);
                ExternalMethodGroup.SelectOverloads(argumentTypes);

                if (ExternalMethodGroup.infos.Length == 0)
                {
                    throw new NotImplementedException();
                }
                else if (ExternalMethodGroup.infos.Length == 1)
                {
                    RedwoodType returnType =
                        RedwoodType.GetForCSharpType(ExternalMethodGroup.infos[0].ReturnType);

                    RedwoodType[] paramTypes = ExternalMethodGroup.infos[0].GetParameters()
                                               .Select(param => RedwoodType.GetForCSharpType(param.ParameterType))
                                               .ToArray();

                    LambdaType = RedwoodType.GetForLambdaArgsTypes(
                        typeof(ExternalLambda),
                        returnType,
                        paramTypes);
                }
            }
        }