public override IRppNode Analyze(SymbolTable scope, Diagnostic diagnostic) { if (TargetType == null) { throw new Exception("TargetType should be specified before anaylyze is called"); } RType classType = TargetType; // TODO It's kinda weird to have resolution here and not in the scope, because similar // lookup is done for methods while (classType != null && Field == null) { Field = classType.Fields.FirstOrDefault(f => f.Name == Name); if (Field != null) { break; } classType = classType.BaseType; } if (Field == null) { var functions = scope.LookupFunction(Name); if (functions.Any(f => f.Parameters.IsEmpty())) { RppFuncCall funcCall = new RppFuncCall(Name, Collections.NoExprs); return funcCall.Analyze(scope, diagnostic); } throw SemanticExceptionFactory.ValueIsNotMember(Token, TargetType.ToString()); } Debug.Assert(classType != null, "obj != null"); Type = new ResolvableType(Field.Type); return this; }
public override void Visit(RppFuncCall node) { Console.WriteLine("Generating func call"); // TODO we should keep references to functions by making another pass of code gen before // real code generation if (node.Name == "ctor()") { _body.Emit(OpCodes.Ldarg_0); ConstructorInfo constructor = typeof(object).GetConstructor(Type.EmptyTypes); Debug.Assert(constructor != null, "constructor != null"); _body.Emit(OpCodes.Call, constructor); } else { // TODO Probably makes more sense to make RppConstructorCall ast, instead of boolean RppMethodInfo rppMethodInfo = node.Function; if (node.IsConstructorCall) { _body.Emit(OpCodes.Ldarg_0); node.Args.ForEach(arg => arg.Accept(this)); var constructor = rppMethodInfo.Native as ConstructorInfo; _body.Emit(OpCodes.Call, constructor); } else { if (!_inSelector) { if (rppMethodInfo.IsStatic) { var instanceField = rppMethodInfo.DeclaringType.Fields.First(f => f.Name == "_instance"); _body.Emit(OpCodes.Ldsfld, instanceField.Native); } else { if (node.IsFromClosure) { _body.Emit(OpCodes.Ldarg_0); Debug.Assert(ClosureContext?.CapturedThis != null, "CapturedThis != null"); _body.Emit(OpCodes.Ldfld, ClosureContext.CapturedThis); } else { _body.Emit(OpCodes.Ldarg_0); // load 'this' } } } // Create own code generator for arguments because they can have RppSelectors which may interfer with already existing RppSelector // myField.CallFunc(anotherInstanceFunc()) would set _inSelector to true and no 'this' will be loaded ClrCodegen codegen = new ClrCodegen(_typeBuilder, _body) {ClosureContext = ClosureContext}; node.Args.ForEach(arg => arg.Accept(codegen)); MethodInfo method = rppMethodInfo.Native as MethodInfo; if (method == null) // This is a stub, so generate code for it { CodegenForStub(rppMethodInfo); return; } Debug.Assert(method != null, "method != null"); if (method.IsGenericMethod) { Type[] methodTypeArgs = node.TypeArgs.Select(t => t.Value.NativeType).ToArray(); if (methodTypeArgs.Length != 0) { method = method.MakeGenericMethod(methodTypeArgs); } } _body.Emit(OpCodes.Callvirt, method); } } }
public override void Visit(RppFuncCall node) { node.Args.ForEach(arg => arg.Accept(this)); }
public virtual void Visit(RppFuncCall node) { }