public GamaFunctionCompiler(GamaNamespaceContext ctx, GamaFunctionRef fn) { NamespaceContext = ctx; Self = fn; Frame = new GamaStackFrame(); Builder = ctx.This.Context.Context.CreateBuilder(); ExpressionCompiler = new GamaExpressionCompiler(this); // This compiler is responsible for compiling most of the function related code // This is why this unit needs to add a block always // All blocks contain a special character in them (such as '.') to avoid mixing user code and compiler generated code // Compiler always works with single block at a time and compiler is single threaded. So this code won't hurt compiler. SetBlock(fn.AddBlock("code")); }
public override GamaValueRef VisitExprOpLogic([NotNull] GamaParser.ExprOpLogicContext context) { var lhs = Visit(context.expr(0)); var rhs = Visit(context.expr(1)); var op = context.opLogic().GetText(); GamaFunctionList oplist; if (op == "&&") { oplist = lhs.Type.Meta.Operators.And; } else if (op == "||") { oplist = lhs.Type.Meta.Operators.Or; } else { oplist = lhs.Type.Meta.Operators.Xor; } var target = !IsEmptyTT ? TopTT : null; GamaFunctionRef fnref = null; if (target == null) { fnref = oplist.FindFunction(new[] { lhs.Type, rhs.Type }); } else { fnref = oplist.FindFunction(target, new[] { lhs.Type, rhs.Type }); } if (fnref == null) { GamaCompiledFunctionList coplist; if (op == "&&") { coplist = lhs.Type.Meta.CompiledOperators.And; } else if (op == "||") { coplist = lhs.Type.Meta.CompiledOperators.Or; } else { coplist = lhs.Type.Meta.CompiledOperators.Xor; } GamaCompiledFunctionRef cfnref = null; if (target == null) { cfnref = coplist.FindFunction(lhs.Type, rhs.Type); } else { cfnref = coplist.FindFunction(target, new[] { lhs.Type, rhs.Type }); } if (cfnref == null) { Parent.NamespaceContext.Context.AddError(new ErrorNoViableOperator(context)); return(null); } var cbuilder = Parent.Builder; Parent.CurrentBlock.PositionBuilderAtEnd(cbuilder); return(cfnref.Call(cbuilder, lhs, rhs)); } /* LLVM */ var block = Parent.CurrentBlock; var builder = Parent.Builder; block.PositionBuilderAtEnd(builder); var result = builder.BuildCall(fnref.Value, new LLVMValueRef[] { lhs.Value, rhs.Value }); return(new GamaValueRef(fnref.ReturnType, result, false)); }
public override GamaValueRef VisitExprOpComp([NotNull] GamaParser.ExprOpCompContext context) { var lhs = Visit(context.expr(0)); var rhs = Visit(context.expr(1)); var op = context.opComp().GetText(); GamaFunctionList oplist; if (op == ">") { oplist = lhs.Type.Meta.Operators.Gt; } else if (op == "<") { oplist = lhs.Type.Meta.Operators.Lt; } else if (op == ">=") { oplist = lhs.Type.Meta.Operators.Ge; } else if (op == "<=") { oplist = lhs.Type.Meta.Operators.Le; } else if (op == "==") { oplist = lhs.Type.Meta.Operators.Eq; } else { oplist = lhs.Type.Meta.Operators.Neq; } GamaFunctionRef fnref = oplist.FindFunction(InstanceTypes.Bool, new[] { lhs.Type, rhs.Type }); if (fnref == null) { GamaCompiledFunctionList coplist; if (op == ">") { coplist = lhs.Type.Meta.CompiledOperators.Gt; } else if (op == "<") { coplist = lhs.Type.Meta.CompiledOperators.Lt; } else if (op == ">=") { coplist = lhs.Type.Meta.CompiledOperators.Ge; } else if (op == "<=") { coplist = lhs.Type.Meta.CompiledOperators.Le; } else if (op == "==") { coplist = lhs.Type.Meta.CompiledOperators.Eq; } else { coplist = lhs.Type.Meta.CompiledOperators.Neq; } GamaCompiledFunctionRef cfnref = coplist.FindFunction(InstanceTypes.Bool, new[] { lhs.Type, rhs.Type }); if (cfnref == null) { Parent.NamespaceContext.Context.AddError(new ErrorNoViableOperator(context)); return(null); } var cbuilder = Parent.Builder; Parent.CurrentBlock.PositionBuilderAtEnd(cbuilder); return(cfnref.Call(cbuilder, lhs, rhs)); } /* LLVM */ var block = Parent.CurrentBlock; var builder = Parent.Builder; block.PositionBuilderAtEnd(builder); var result = builder.BuildCall(fnref.Value, new LLVMValueRef[] { lhs.Value, rhs.Value }); return(new GamaValueRef(fnref.ReturnType, result, false)); }
public override bool VisitStructLevelMethod([NotNull] GamaParser.StructLevelMethodContext context) { var fndef = context.topLevelFuncDef(); var name = fndef.Symbol().GetText(); GamaFunctionList fnlist = null; if (name == "new") { fnlist = StructType.Meta.Constructors; } else { fnlist = StructType.Meta.GetMethod(name); } if (fnlist == null) { fnlist = new GamaFunctionList(name); StructType.Meta.Methods.Add(fnlist); } var retty = InstanceTypes.Void; var tyname = fndef.typeName(); if (tyname != null) { retty = Parent.NamespaceContext.FindTypeRefGlobal(tyname); if (retty == null) { Parent.GlobalContext.AddError(new ErrorTypeNotFound(tyname)); return(false); } } var stplist = fndef.symbolTypePairList(); var paramlist = new GamaParamList(); paramlist.Add("this", new GamaPointer(StructType)); // add self as a pointer since this is a method if (stplist != null) { var pairs = stplist.symbolTypePair(); foreach (var p in pairs) { var ty = Parent.NamespaceContext.FindTypeRefGlobal(p.typeName()); if (ty == null) { Parent.GlobalContext.AddError(new ErrorTypeNotFound(p.typeName())); return(false); } if (!paramlist.Add(p.Symbol().GetText(), ty)) { Parent.GlobalContext.AddError(new ErrorDuplicateParameter(p)); return(false); } } } if (fnlist.FindFunction(paramlist) != null) { Parent.GlobalContext.AddError(new ErrorDuplicateMethod(fndef)); return(false); } var modty = new GamaFunction(retty, paramlist.Parameters.Select(p => p.Type).ToArray(), LLVMTypeRef.CreateFunction(retty.UnderlyingType, paramlist.Parameters.Select(p => p.Type.UnderlyingType).ToArray())); var modfn = Parent.GlobalContext.Module.AddFunction($"{ StructType.Name }.{ name }", modty.UnderlyingType); var fn = new GamaFunctionRef(retty, paramlist, modty, modfn, true); /* Parameters are added to top frame of the target function, but they are not treated as conventional variables */ var unit = new GamaFunctionCompiler(Parent.NamespaceContext, fn); foreach (var p in paramlist.Parameters) { unit.Top.AddValue(p.Name, new GamaValueRef(p.Type, modfn.GetParam(p.Index), false)); } unit.Visit(fndef.block()); if (unit.Finish() == 0) { // TODO: handle type method attributes fnlist.AddFunction(fn); } else { ; } return(true); }
public override bool VisitTopLevelFuncDef([NotNull] GamaParser.TopLevelFuncDefContext context) { var name = context.Symbol().GetText(); var fnlist = NamespaceContext.FindFunctionRef(name); var attrs = context.funcAttr(); // New function if (fnlist == null) { fnlist = new GamaFunctionList(name); var stplist = context.symbolTypePairList(); var parms = new GamaParamList(); var parmTypes = new GamaTypeRef[0]; var parmTypesNative = new LLVMTypeRef[0]; if (stplist != null) { var list = stplist.symbolTypePair(); parmTypes = new GamaTypeRef[list.Length]; parmTypesNative = new LLVMTypeRef[list.Length]; for (int i = 0; i < list.Length; i++) { var stp = list[i]; var sym = stp.Symbol(); var type = NamespaceContext.FindTypeRefGlobal(stp.typeName()); if (type == null) { GlobalContext.AddError(new ErrorTypeNotFound(stp.typeName())); return(false); } /* Since functions are not first-class types, we need to wrap them around with a pointer */ if (type is GamaFunction) { type = new GamaPointer(type); } if (!parms.Add(sym.GetText(), type)) { GlobalContext.AddError(new ErrorDuplicateParameter(stp)); return(false); // TODO: fix error library. } parmTypesNative[i] = type.UnderlyingType; parmTypes[i] = type; } } /* Determine type */ var rettypefqtn = context.typeName(); var retty = InstanceTypes.Void; // If function has a non-void type if (rettypefqtn != null) { // Find it retty = NamespaceContext.FindTypeRefGlobal(rettypefqtn); if (retty == null) { GlobalContext.AddError(new ErrorTypeNotFound(rettypefqtn)); return(false); } } /* LLVM */ var modty = new GamaFunction(retty, parmTypes, LLVMTypeRef.CreateFunction(retty.UnderlyingType, parmTypesNative)); var modfn = NamespaceContext.This.Context.Module.AddFunction(name, modty.UnderlyingType); var fn = new GamaFunctionRef(retty, parms, modty, modfn, false); var unit = new GamaFunctionCompiler(NamespaceContext, fn); /* Parameters are added to top frame of the target function, but they are not treated as conventional variables */ foreach (var p in parms.Parameters) { unit.Top.AddValue(p.Name, new GamaValueRef(p.Type, modfn.GetParam(p.Index), false)); } unit.Visit(context.block()); if (unit.Finish() == 0) { // First add ident, if it fails you fail too. if (attrs != null) { var attributes = new GamaAttributeCompiler(this).Visit(attrs); if (attributes != null) { fn.Attributes = attributes; } else { return(false); } } fnlist.AddFunction(fn); NamespaceContext.This.Functions.Add(fnlist); } else { ; // ?gnihtemos oD :ODOT (TODO:) } return(true); } // An override function else { var stplist = context.symbolTypePairList(); var parms = new GamaParamList(); if (stplist != null) { var list = stplist.symbolTypePair(); for (int i = 0; i < list.Length; i++) { var stp = list[i]; var sym = stp.Symbol(); var type = NamespaceContext.FindTypeRefGlobal(stp.typeName()); if (type == null) { GlobalContext.AddError(new ErrorTypeNotFound(stp.typeName())); return(false); } if (type is GamaFunction) { if (!parms.Add(sym.GetText(), new GamaPointer(type))) { GlobalContext.AddError(new ErrorDuplicateParameter(stp)); return(false); // TODO: fix error library. } continue; } if (!parms.Add(sym.GetText(), type)) { GlobalContext.AddError(new ErrorDuplicateParameter(stp)); return(false); } } } // Duplicate function if two functions have same type of parameters if (fnlist.FindFunction(parms) != null) { GlobalContext.AddError(new ErrorDuplicateFunction(context)); return(false); } /* Determine type */ var rettypefqtn = context.typeName(); var retty = InstanceTypes.Void; // If function has a non-void type if (rettypefqtn != null) { // Find it retty = NamespaceContext.FindTypeRefGlobal(rettypefqtn); if (retty == null) { GlobalContext.AddError(new ErrorTypeNotFound(rettypefqtn)); return(false); } } var modty = new GamaFunction(retty, parms.Parameters.Select(p => p.Type).ToArray(), LLVMTypeRef.CreateFunction(retty.UnderlyingType, parms.Parameters.Select(p => p.Type.UnderlyingType).ToArray())); var modfn = GlobalContext.Module.AddFunction(name, modty.UnderlyingType); var fn = new GamaFunctionRef(retty, parms, modty, modfn, false); var unit = new GamaFunctionCompiler(NamespaceContext, fn); unit.Visit(context.block()); if (unit.Finish() == 0) { if (attrs != null) { var attributes = new GamaAttributeCompiler(this).Visit(attrs); if (attributes != null) { fn.Attributes = attributes; } else { return(false); } } fnlist.AddFunction(fn); } else { ; // TODO: } return(true); } }
public override bool VisitTopLevelExternDef([NotNull] GamaParser.TopLevelExternDefContext context) { var name = context.Symbol().GetText(); var list = NamespaceContext.FindFunctionRefGlobal(name); if (list == null) { list = new GamaFunctionList(name); NamespaceContext.This.Functions.Add(list); } var retty = InstanceTypes.Void; var rettyfqtn = context.typeName(); if (rettyfqtn != null) { retty = NamespaceContext.FindTypeRefGlobal(rettyfqtn); if (retty == null) { GlobalContext.AddError(new ErrorTypeNotFound(context.typeName())); return(false); } } var ellipsis = context.ellipsis() != null; var parmslist = new GamaParamList(); var argtypes = new GamaTypeRef[0]; var argtypesnative = new LLVMTypeRef[0]; var fqtnlist = context.typeList(); if (fqtnlist != null) { var types = fqtnlist.typeName(); argtypesnative = new LLVMTypeRef[types.Length]; argtypes = new GamaTypeRef[types.Length]; for (int i = 0; i < types.Length; i++) { var ty = NamespaceContext.FindTypeRefGlobal(types[i]); if (ty == null) { GlobalContext.AddError(new ErrorTypeNotFound(types[i])); return(false); } parmslist.Add(i.ToString(), ty); // Adding parameter with a numeric name, doesn't matter since this is a extern. argtypes[i] = ty; argtypesnative[i] = ty.UnderlyingType; } } if (list.FindFunction(parmslist) != null) { GlobalContext.AddError(new ErrorDuplicateFunction(context)); return(false); } var fnty = new GamaFunction(retty, argtypes, LLVMTypeRef.CreateFunction(retty.UnderlyingType, argtypesnative, ellipsis), ellipsis); var modfn = GlobalContext.Module.AddFunction(name, fnty.UnderlyingType); var fnref = new GamaFunctionRef(retty, parmslist, fnty, modfn, false); list.AddFunction(fnref); return(true); }