public override void CheckSemantic(SymbolTable symbolTable, List <CompileError> errors) { SemanticInfo variableInfo; ///chequeamos que no haya una variable con el mismo nombre if (symbolTable.GetDefinedVariableShallow(CallableId, out variableInfo)) { errors.Add(new CompileError { Line = GetChild(ChildCount - 2).Line, Column = GetChild(ChildCount - 2).CharPositionInLine, ErrorMessage = string.Format("There is already a definition for '{0}' in current context", CallableId), Kind = ErrorKind.Semantic }); ///el nodo evalúa de error NodeInfo = SemanticInfo.SemanticError; } ///creamos el scope de la función o procedimiento symbolTable.InitNewScope(); SemanticInfo param; ///agregamos los parámetros de la función o procedimiento al scope for (int i = 0; i < Parameters.Count; i++) { param = new SemanticInfo { Name = Parameters[i].Key, ElementKind = SymbolKind.Variable, BuiltInType = parametersType[i].BuiltInType, Type = parametersType[i], ElementsType = parametersType[i].ElementsType, Fields = parametersType[i].Fields }; symbolTable.InsertSymbol(param); } ///check semantics al CallableBody CallableBody.CheckSemantic(symbolTable, errors); ///destruimos el scope de la función o procedimiento symbolTable.CloseCurrentScope(); }
public override void GenerateCode(ILCodeGenerator cg) { if (FirstPass) { if (this is FunctionDeclarationNode) { ILElementInfo returnILElementInfo = cg.ILContextTable.GetDefinedType((this as FunctionDeclarationNode).ReturnType); returnILType = returnILElementInfo.ILType; if (Object.Equals(returnILType, null)) { returnILType = (this as FunctionDeclarationNode).functionParche.ILType; } } for (int i = 0; i < ILTypes.Count; i++) { if (Object.Equals(ILTypes[i], null)) { ILTypes[i] = parametersType[i].Type.ILType; } } ///creamos un método estático en la clase Program string callableName = string.Format("{0}{1}", CallableId, cg.ILContextTable.ContextNumber); MethodBuilder callable = cg.Program.DefineMethod(callableName, MethodAttributes.Private | MethodAttributes.Static, returnILType, ILTypes.ToArray()); ///lo insertamos el la tabla de contextos cg.ILContextTable.InsertILElement(CallableId, new ILElementInfo { MethodBuilder = callable, ElementKind = SymbolKind.Function }); ///ya no va a ser la 1era pasada FirstPass = false; } else { ILElementInfo callable = cg.ILContextTable.GetDefinedVarOrFunction(CallableId); MethodBuilder callableBuilder = callable.MethodBuilder; ILGenerator tmpIL = cg.ILGenerator; cg.ILGenerator = callableBuilder.GetILGenerator(); ///creamos un nuevo contexto cg.ILContextTable.InitNewContext(); List <LocalBuilder> localSaving = new List <LocalBuilder>(); ///creamos los parámetros y variables en la clase Program for (int i = 0; i < Parameters.Count; i++) { ParameterBuilder pb = callableBuilder.DefineParameter(i + 1, ParameterAttributes.None, Parameters[i].Key); string parameterName = string.Format("{0}{1}", Parameters[i].Key, cg.ILContextTable.ContextNumber); FieldBuilder fb = cg.Program.DefineField(parameterName, ILTypes[i], FieldAttributes.Public | FieldAttributes.Static); cg.ILContextTable.InsertILElement(Parameters[i].Key, new ILElementInfo { FieldBuilder = fb, ElementKind = SymbolKind.Variable }); } //salvamos los valores de las variables de la clase for (int i = 0; i < Parameters.Count; i++) { localSaving.Add(cg.ILGenerator.DeclareLocal(ILTypes[i])); callable = cg.ILContextTable.GetDefinedVarOrFunction(Parameters[i].Key); cg.ILGenerator.Emit(OpCodes.Ldsfld, callable.FieldBuilder); cg.ILGenerator.Emit(OpCodes.Stloc, localSaving[i]); } ///cargando los argumentos for (int i = 0; i < Parameters.Count; i++) { callable = cg.ILContextTable.GetDefinedVarOrFunction(Parameters[i].Key); cg.ILGenerator.Emit(OpCodes.Ldarg, i); cg.ILGenerator.Emit(OpCodes.Stsfld, callable.FieldBuilder); } ///gen code al body de la función o procedimiento CallableBody.GenerateCode(cg); bool isFunction = this is FunctionDeclarationNode; LocalBuilder returnValue = null; ///en caso de ser función if (isFunction) { returnValue = cg.ILGenerator.DeclareLocal(returnILType); cg.ILGenerator.Emit(OpCodes.Stloc, returnValue); } ///restauramos los valores de las variables de la clase for (int i = 0; i < Parameters.Count; i++) { callable = cg.ILContextTable.GetDefinedVarOrFunction(Parameters[i].Key); cg.ILGenerator.Emit(OpCodes.Ldloc, localSaving[i]); cg.ILGenerator.Emit(OpCodes.Stsfld, callable.FieldBuilder); } List <KeyValuePair <LocalBuilder, FieldBuilder> > localvars = CallableBody.GetLocalVariableDeclarations(); foreach (var item in localvars) { cg.ILGenerator.Emit(OpCodes.Ldloc, item.Key); cg.ILGenerator.Emit(OpCodes.Stsfld, item.Value); } ///destruimos el contexto de la función o procedimiento cg.ILContextTable.CloseCurrentContext(); ///si es función ponemos en el tope de la pila el valor de retorno if (isFunction) { cg.ILGenerator.Emit(OpCodes.Ldloc, returnValue); } ///emitimos el return de la función cg.ILGenerator.Emit(OpCodes.Ret); ///restauramos el ILGenerator del cg cg.ILGenerator = tmpIL; } }