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); }
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); }
internal override IEnumerable <Instruction> Compile() { List <Instruction> instructions = new List <Instruction>(); instructions.AddRange(Chain.Compile()); RedwoodType chainType = Chain.GetKnownType(); if (chainType == null) { instructions.Add(new LookupExternalMemberInstruction(Element.Name, null)); } else if (chainType.CSharpType == null) { if (!chainType.slotMap.ContainsKey(Element.Name)) { throw new NotImplementedException(); } instructions.Add(new LookupDirectMemberInstruction(chainType.slotMap[Element.Name])); } else { // TODO: Should this be a special reflected instruction? instructions.Add(new LookupExternalMemberInstruction(Element.Name, chainType)); } return(instructions); }
internal override void Bind(Binder binder) { DeclaredVariable.KnownType = RedwoodType.GetForLambdaArgsTypes( typeof(InternalLambda), ReturnType == null ? RedwoodType.Void : ReturnType.GetIndicatedType(), Parameters.Select(param => param.Type.GetIndicatedType()).ToArray()); base.Bind(binder); // No need to bind if we're a stub; we just need to communicate // our type to the outside world. Since no actual compilation will // go on, we don't need to be compiled. if (Body == null) { return; } binder.EnterFullScope(); binder.PushReturnType( ReturnType == null ? RedwoodType.Void : ReturnType.GetIndicatedType() ); foreach (ParameterDefinition param in Parameters) { param.Bind(binder); } Body.Bind(binder); ClosureSize = binder.GetClosureSize(); binder.PopReturnType(); StackSize = binder.LeaveFullScope(); }
internal InternalLambdaDescription CompileInner() { List <Instruction> bodyInstructions = new List <Instruction>(); RedwoodType[] paramTypes = new RedwoodType[Parameters.Length]; for (int i = 0; i < Parameters.Length; i++) { paramTypes[i] = Parameters[i].DeclaredVariable.KnownType; bodyInstructions.AddRange(Parameters[i].Compile()); } bodyInstructions.AddRange(Body.Compile()); if (ReturnType == null || ReturnType.GetIndicatedType() == RedwoodType.Void) { bodyInstructions.Add(new ReturnInstruction()); } return(new InternalLambdaDescription { argTypes = paramTypes, returnType = ReturnType == null ? RedwoodType.Void : ReturnType?.GetIndicatedType(), instructions = bodyInstructions.ToArray(), stackSize = StackSize, closureSize = ClosureSize, ownerSlot = DeclaredVariable.Location // TODO: is this right? }); }
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()); }
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); } } }
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]); }
public override RedwoodType GetKnownType() { if (Value < int.MaxValue && Value > int.MinValue) { return(RedwoodType.GetForCSharpType(typeof(int))); } return(RedwoodType.GetForCSharpType(typeof(BigInteger))); }
internal InPlaceLambda( RedwoodType[] argumentTypes, RedwoodType returnType, InPlaceLambdaExecutor executor) { this.argumentTypes = argumentTypes; ReturnType = returnType; this.executor = executor; }
internal static IEnumerable <Instruction> CompileImplicitConversion( RedwoodType from, RedwoodType to) { if (to == null) { // If we have a null destination, this shouldn't // even get called; we will be resolving it closer // to runtime throw new ArgumentException("Cannot convert to dynamic type"); } if (from == null) { return(new Instruction[] { new DynamicConvertInstruction(to) }); } else if (to.IsAssignableFrom(from)) { // In this case, we are a subtype or the correct type // so we don't need to do anything return(new Instruction[0]); } else if (from.HasImplicitConversion(to)) { if (from.CSharpType == null) { if (!from.HasImplicitConversion(to)) { throw new NotImplementedException(); } int slot = from.implicitConversionMap[to]; return(new Instruction[] { new LookupDirectMemberInstruction(slot), new InternalCallInstruction(new int[0]) }); } // This call won't work on a RedwoodType in the compile phase // because the static lambdas aren't populated yet return(new Instruction[] { new CallWithResultInstruction( RuntimeUtil.GetConversionLambda(from, to) ) }); } else { // Cannot convert between the types throw new NotImplementedException(); } }
public TryCallInstruction( string functionName, RedwoodType calleeTypeHint, RedwoodType[] argTypesHint, int[] argLocations) { this.functionName = functionName; this.calleeTypeHint = calleeTypeHint; this.argTypesHint = argTypesHint; this.argLocations = argLocations; }
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; }
public LookupExternalMemberBinaryOperationInstruction( BinaryOperator op, int leftIndex, int rightIndex, RedwoodType leftKnownType, RedwoodType rightKnownType) { this.op = op; this.leftIndex = leftIndex; this.rightIndex = rightIndex; this.leftKnownType = leftKnownType; this.rightKnownType = rightKnownType; }
private void CompileCallNoCallee( List <Instruction> instructions, RedwoodType[] argumentTypes, int[] argumentLocations, RedwoodType knownType) { if (knownType == null) { instructions.Add(new TryCallInstruction(argumentTypes, argumentLocations)); } else if (knownType.CSharpType == typeof(InternalLambda)) { instructions.Add(new InternalCallInstruction(argumentLocations)); } else if (knownType.CSharpType == typeof(ExternalLambda)) { instructions.Add(new ExternalCallInstruction(argumentLocations)); } else if (knownType.CSharpType == typeof(LambdaGroup)) { if (FullyResolved && knownType.GenericArguments != null) { RuntimeUtil.TrySelectOverload( argumentTypes, knownType.GenericArguments .Select(lambdaType => lambdaType .GenericArguments .SkipLast(1) .ToArray() ) .ToArray(), out int index ); instructions.Add(new LookupLambdaGroupOverloadInstruction(index)); instructions.Add(new ExternalCallInstruction(argumentLocations)); } else { instructions.Add(new TryCallInstruction(argumentTypes, argumentLocations)); } } else if (knownType.CSharpType == typeof(RedwoodType)) { instructions.Add(new LookupExternalMemberLambdaInstruction("Constructor", knownType)); instructions.Add(new ExternalCallInstruction(argumentLocations)); } else { throw new NotImplementedException(); } }
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); }
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); }
public int Execute(Frame frame) { RedwoodType leftType = leftKnownType ?? RuntimeUtil.GetTypeOf(frame.stack[leftIndex]); RedwoodType rightType = rightKnownType ?? RuntimeUtil.GetTypeOf(frame.stack[rightIndex]); string lambdaName = RuntimeUtil.NameForOperator(op); Lambda leftLambda; Lambda rightLambda; leftLambda = ResolveLambda(leftType, lambdaName); rightLambda = ResolveLambda(rightType, lambdaName); Lambda lambda = RuntimeUtil.CanonicalizeLambdas(leftLambda, rightLambda); lambda = RuntimeUtil.SelectSingleOverload( new RedwoodType[] { leftType, rightType }, lambda ); frame.result = lambda; return(1); Lambda ResolveLambda(RedwoodType type, string lambdaName) { Lambda lambda; if (type.CSharpType == null) { int slot = type.staticSlotMap.GetValueOrDefault(lambdaName, -1); if (slot == -1) { lambda = null; } else { lambda = type.staticLambdas[slot]; } } else { MemberResolver.TryResolveLambda(null, type, lambdaName, out lambda); } return(lambda); } }
public void IsType(RedwoodType type, object item) { AssertionsCount++; Assert.NotNull(type); Assert.NotNull(item); if (item is RedwoodObject ro) { Assert.Null(type.CSharpType); Assert.Equal(type, ro.Type); } else { Assert.NotNull(type.CSharpType); Assert.Equal(type.CSharpType, item.GetType()); } }
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()); }
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()); }
private IEnumerable <Instruction> CompileAssign() { RedwoodType leftType = Left.GetKnownType(); RedwoodType rightType = Right.GetKnownType(); List <Instruction> instructions = new List <Instruction>(); instructions.AddRange(Right.Compile()); // If leftType == null, then the left must be responsible for // attempting to convert to the correct type if (leftType != null) { instructions.AddRange( Compiler.CompileImplicitConversion(rightType, leftType) ); } instructions.AddRange(Left.CompileAssignmentTarget(TemporaryVariables)); return(instructions.ToArray()); }
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); }
internal RedwoodType GetIndicatedType() { RedwoodType knownType = TypeName.Constant ? TypeName.EvaluateConstant() as RedwoodType : null; if (GenericInnerTypes == null) { return(knownType); } else if (knownType.CSharpType == null) { // TODO: Just compile dynamic checks where necessary? throw new NotImplementedException(); } else { knownType.CSharpType.MakeGenericType( GenericInnerTypes.Select(typeSyntax => { RedwoodType genericType = typeSyntax.GetIndicatedType(); // TODO? if (genericType == null) { return(typeof(object)); } // Definitely TODO... I guess this will just happen // with dynamic checks everywhere? if (genericType.CSharpType == null) { return(typeof(RedwoodObject)); } return(genericType.CSharpType); }).ToArray() ); throw new NotImplementedException(); } }
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]); }
private IEnumerable <Instruction> CompileAs() { // Make sure that the right resolved to a type if (!Right.Constant) { throw new NotImplementedException(); } RedwoodType rightValue = Right.EvaluateConstant() as RedwoodType; if (rightValue == null) { throw new NotImplementedException(); } List <Instruction> instructions = new List <Instruction>(); instructions.AddRange(Left.Compile()); instructions.AddRange( Compiler.CompileImplicitConversion(Left.GetKnownType(), rightValue) ); return(instructions); }
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); }
public override RedwoodType GetKnownType() { return(RedwoodType.GetForCSharpType(typeof(RedwoodType))); }
public SetStaticOverloadInstruction(RedwoodType type, int index) { this.type = type; this.index = index; }
public BuildRedwoodObjectFromClosureInstruction(RedwoodType type) { this.type = type; }