public override bool VisitClassDeclarationStatements_Ex([NotNull] ClepsParser.ClassDeclarationStatementsContext context) { if (!ClassManager.IsClassBuilderAvailable(FullyQualifiedClassName)) { //if the class was not found in the loaded class stage, then this is probably due to an earlier parsing error, just stop processing this class return(false); } if (ClassManager.IsClassBodySet(FullyQualifiedClassName)) { //class body is already set //this branch is hit, if the user has an error in code where multiple classes have the same name //gracefully exit return(false); } Visit(context.classBodyStatements()); ClepsClassBuilder classBuilder = ClassManager.GetClassBuilder(FullyQualifiedClassName); ClepsClass classDetails = classBuilder.BuildClass(); ClassManager.SetClassDefinition(classDetails); CodeGenerator.SetClassBodyAndCreateConstructor(classDetails); return(true); }
private LLVMRegister GenerateAssignmentToRegister(ParserRuleContext context, LLVMRegister targetPtrRegister, LLVMRegister assignmentValuePtrRegister, string assignmentOperator) { string targetClassName = targetPtrRegister.VariableType.RawTypeName; LLVMValueRef assignmentValue = LLVM.BuildLoad(Builder, assignmentValuePtrRegister.LLVMPtrValueRef, "assignmentValue"); if (ClepsLLVMTypeConvertorInst.IsPrimitiveLLVMType(targetPtrRegister.VariableType)) { //if it is a primitive llvmType, the assignment operators are hardcoded //only the = assignment operator is supported for primitive llvm types if (assignmentOperator != "=") { string errorMessage = String.Format("Primitive class {0} does not have assignment operator {1} defined. = is the only assignment operator allowed", targetClassName, assignmentOperator); Status.AddError(new CompilerError(FileName, context.Start.Line, context.Start.Column, errorMessage)); return(null); } if (targetPtrRegister.VariableType != assignmentValuePtrRegister.VariableType) { string errorMessage = String.Format("Value of type {0} cannot be assigned to variable of type {1}", assignmentValuePtrRegister.VariableType, targetPtrRegister.VariableType); Status.AddError(new CompilerError(FileName, context.Start.Line, context.Start.Column, errorMessage)); return(null); } LLVM.BuildStore(Builder, assignmentValue, targetPtrRegister.LLVMPtrValueRef); return(null); } else { ClepsClass variableClass = ClassManager.LoadedClassesAndMembers[targetClassName]; if (!variableClass.MemberMethods.ContainsKey(assignmentOperator)) { string errorMessage = String.Format("The class {0} does not have assignment operator {1} defined", targetClassName, assignmentOperator); Status.AddError(new CompilerError(FileName, context.Start.Line, context.Start.Column, errorMessage)); return(null); } ClepsType assignmentFunctionToCall = variableClass.MemberMethods[assignmentOperator]; if (assignmentFunctionToCall.FunctionParameters.Count != 2 && assignmentFunctionToCall.FunctionParameters[1] != assignmentValuePtrRegister.VariableType) { string errorMessage = String.Format("The class {0} does not have an assignment operator {1} defined that takes parameter {2}", targetClassName, assignmentOperator, assignmentValuePtrRegister.VariableType); Status.AddError(new CompilerError(FileName, context.Start.Line, context.Start.Column, errorMessage)); return(null); } string assignmentFunctionNameToCall = String.Format("{0}.{1}", targetClassName, assignmentOperator); LLVMValueRef llvmAssignmentFunction = LLVM.GetNamedFunction(Module, assignmentFunctionNameToCall); LLVMValueRef[] parameters = new LLVMValueRef[] { targetPtrRegister.LLVMPtrValueRef, assignmentValue }; LLVM.BuildCall(Builder, llvmAssignmentFunction, parameters, ""); return(null); } }
private void ValidateClass(ParserRuleContext context, ClepsClass clepsClass) { ClepsType rawLLVMTypeMap = clepsClass.RawLLVMTypeMap; if (rawLLVMTypeMap != null) { ClepsType firstMember = clepsClass.MemberVariables.Values.FirstOrDefault(); if (firstMember != rawLLVMTypeMap) { string errorMessage = String.Format("Class {0} is mapped to the raw llvm type {1}. However the first member of this class is of type {2}", clepsClass.FullyQualifiedName, clepsClass.RawLLVMTypeMap.GetTypeName(), firstMember.GetTypeName()); Status.AddError(new CompilerError(FileName, context.Start.Line, context.Start.Column, errorMessage)); } } }
public void SetClassBodyAndCreateConstructor(ClepsClass clepsClass) { if (!classesLoaded.ContainsKey(clepsClass.FullyQualifiedName)) { throw new ArgumentException(String.Format("Class {0} not loaded", clepsClass.FullyQualifiedName)); } if (classesLoaded[clepsClass.FullyQualifiedName] != null) { throw new ArgumentException(String.Format("Body for class {0} already set", clepsClass.FullyQualifiedName)); } classesLoaded[clepsClass.FullyQualifiedName] = clepsClass; }
public override LLVMRegister VisitIfStatement([NotNull] ClepsParser.IfStatementContext context) { ClepsParser.RightHandExpressionContext condition = context.rightHandExpression(); LLVMRegister expressionValue = Visit(condition); ClepsType nativeBooleanType = ClepsType.GetBasicType("System.LLVMTypes.I1", 0 /* ptr indirection level */); LLVMValueRef?conditionRegisterPtr = null; //handle native llvm boolean type if (expressionValue.VariableType == nativeBooleanType) { conditionRegisterPtr = expressionValue.LLVMPtrValueRef; } //handle cleps llvm boolean type else if (ClassManager.RawLLVMTypeMappingClasses.ContainsKey(nativeBooleanType)) { ClepsClass mappedBooleanClass = ClassManager.RawLLVMTypeMappingClasses[nativeBooleanType]; ClepsType mappedBooleanType = ClepsType.GetBasicType(mappedBooleanClass.FullyQualifiedName, 0 /* ptr indirection level */); if (expressionValue.VariableType == mappedBooleanType) { //if the mapped type exists, then below can never be null, so call value automatically LLVMTypeRef mappedBooleanTypeInLLVM = ClepsLLVMTypeConvertorInst.GetLLVMTypeOrNull(mappedBooleanType).Value; //get the first field in the mapped type - see rawtypemap for more details conditionRegisterPtr = LLVM.BuildStructGEP(Builder, expressionValue.LLVMPtrValueRef, 0, "ifCondBooleanFieldPtr"); } } if (conditionRegisterPtr == null) { string errorMessage = String.Format("The condition expression in the if condition returns type {0} instead of a boolean expression. ", expressionValue.VariableType.GetTypeName()); Status.AddError(new CompilerError(FileName, context.Start.Line, context.Start.Column, errorMessage)); //just assume this is condition is true to avoid stalling the compilation conditionRegisterPtr = LLVM.ConstInt(LLVM.Int1TypeInContext(Context), (ulong)1, false); } LLVMValueRef conditionRegister = LLVM.BuildLoad(Builder, conditionRegisterPtr.Value, "ifCondBooleanField"); LLVMValueRef currentFunction = LLVM.GetInsertBlock(Builder).GetBasicBlockParent(); LLVMBasicBlockRef ifThenBlock = LLVM.AppendBasicBlockInContext(Context, currentFunction, "ifthen"); LLVMBasicBlockRef ifEndBlock = LLVM.AppendBasicBlockInContext(Context, currentFunction, "ifend"); LLVM.BuildCondBr(Builder, conditionRegister, ifThenBlock, ifEndBlock); LLVM.PositionBuilderAtEnd(Builder, ifThenBlock); Visit(context.statementBlock()); LLVM.BuildBr(Builder, ifEndBlock); LLVM.PositionBuilderAtEnd(Builder, ifEndBlock); return(expressionValue); }
private void EnsureNamespaceExists(StringBuilder output, ClepsClass clepsClass) { string currNamespace = clepsClass.GetNamespace(); var pieces = currNamespace.Split('.').ToList(); for (int i = 1; i <= pieces.Count; i++) { var currNesting = String.Join(".", pieces.Take(i)); if (!namespacesCreated.Contains(currNesting)) { output.AppendFormat("{0}.{1} = {0}.{1} || {{}};\n", TOPLEVELNAMESPACE, currNesting); namespacesCreated.Add(currNesting); } } }
private void GenerateClass(StringBuilder output, ClepsClass clepsClass) { FunctionClepsType voidFuncType = new FunctionClepsType(new List <ClepsType>(), VoidClepsType.GetVoidType()); EnsureNamespaceExists(output, clepsClass); output.AppendLine(JavaScriptCodeParameters.TOPLEVELNAMESPACE + "." + clepsClass.FullyQualifiedName + " = function() {"); { clepsClass.MemberVariables.ToList().ForEach(kvp => output.AppendFormat("\tthis.{0} = undefined;\n", kvp.Key)); output.AppendFormat("\tthis.{0}();\n", JavaScriptCodeParameters.GetMangledFunctionName("classInitializer", voidFuncType)); output.AppendFormat("\t{0}.{1}.{2}();\n", JavaScriptCodeParameters.TOPLEVELNAMESPACE, clepsClass.FullyQualifiedName, JavaScriptCodeParameters.GetMangledFunctionName("classStaticInitializer", voidFuncType)); } output.AppendLine("};"); GenerateMethodWithBody(output, clepsClass.FullyQualifiedName, "classInitializer", voidFuncType, false, ClassInitializers[clepsClass.FullyQualifiedName]); GenerateMethodWithBody(output, clepsClass.FullyQualifiedName, "classStaticInitializer", voidFuncType, true, ClassStaticInitializers[clepsClass.FullyQualifiedName]); }
private void GenerateClass(StringBuilder output, ClepsClass clepsClass) { EnsureNamespaceExists(output, clepsClass); //output.AppendLine(TOPLEVELNAMESPACE + "." + clepsClass.FullyQualifiedName + " = function() {"); //{ // output.AppendLine("\tfunction newInst(curr) {"); // { // clepsClass.MemberVariables.ToList().ForEach(kvp => output.AppendFormat("\t\tcurr.{0} = {1};\n", kvp.Key, GetTypeInstance(kvp.Value))); // output.AppendLine("\t}"); // } // output.AppendLine("\tnewInst(this);"); //} //output.AppendLine("};"); //clepsClass.MemberMethods.ToList().ForEach(kvp => output.AppendFormat("{0}.{1}.prototype.{2} = {3};\n", TOPLEVELNAMESPACE, clepsClass.FullyQualifiedName, kvp.Key, methodBodies[new FunctionNameAndType(clepsClass.FullyQualifiedName, kvp.Key, kvp.Value)].GetMethodBody())); //clepsClass.StaticMemberVariables.ToList().ForEach(kvp => output.AppendFormat("{0}.{1}.{2} = undefined;\n", TOPLEVELNAMESPACE, clepsClass.FullyQualifiedName, kvp.Key)); //clepsClass.StaticMemberMethods.ToList().ForEach(kvp => output.AppendFormat("{0}.{1}.{2} = {3};\n", TOPLEVELNAMESPACE, clepsClass.FullyQualifiedName, kvp.Key, methodBodies[new FunctionNameAndType(clepsClass.FullyQualifiedName, kvp.Key, kvp.Value)].GetMethodBody())); GenerateJavaScriptClass(output, clepsClass.FullyQualifiedName, clepsClass.MemberVariables, clepsClass.MemberMethods, true /* staticInstCheck */); GenerateJavaScriptClass(output, clepsClass.FullyQualifiedName + ".static", clepsClass.StaticMemberVariables, clepsClass.StaticMemberMethods, false /* staticInstCheck */); }
public override object VisitFieldOrClassAssignment([NotNull] ClepsParser.FieldOrClassAssignmentContext context) { List <string> namespaceClassAndFieldHierarchy = context._ClassHierarchy.Select(h => h.GetText()).ToList(); bool classFound = false; int i; for (i = namespaceClassAndFieldHierarchy.Count; i >= 1; i--) { string classNameToTest = String.Join(".", namespaceClassAndFieldHierarchy.Take(i).ToList()); if (ClassManager.IsClassBodySet(classNameToTest)) { classFound = true; break; } } if (!classFound) { string errorMessage = String.Format("Could not find class or field {0}", String.Join(".", namespaceClassAndFieldHierarchy)); Status.AddError(new CompilerError(FileName, context.Start.Line, context.Start.Column, errorMessage)); //just return something to avoid stalling return(CodeGenerator.CreateByte(0)); } string fullClassName = String.Join(".", namespaceClassAndFieldHierarchy.Take(i).ToList()); ClepsClass currentClass = ClassManager.GetClass(fullClassName); BasicStaticClepsType currentType = new BasicStaticClepsType(fullClassName); var fieldAccesses = namespaceClassAndFieldHierarchy.Skip(i).ToList(); if (fieldAccesses.Count != 0) { throw new NotImplementedException("Getting fields on static classes is not supported yet"); } IValue ret = CodeGenerator.GetClassStaticInstance(currentType); return(ret); }
public void SetClassBodyAndCreateConstructor(ClepsClass clepsClass) { var memberTypes = clepsClass.MemberVariables.Values.Select(c => GetLLVMType(c)).ToArray(); LLVM.StructSetBody(ClassSkeletons[clepsClass.FullyQualifiedName], memberTypes, false /* packed */); }
public override LLVMRegister VisitBinaryOperatorOnExpression([NotNull] ClepsParser.BinaryOperatorOnExpressionContext context) { LLVMRegister leftExpression = Visit(context.LeftExpression); LLVMRegister rightExpression = Visit(context.RightExpression); if (leftExpression.VariableType != rightExpression.VariableType) { throw new NotImplementedException("Operators on different types are not yet supported"); } string expressionClassName = leftExpression.VariableType.RawTypeName; string operatorName = context.operatorSymbol().GetText(); if (ClepsLLVMTypeConvertorInst.IsPrimitiveLLVMType(leftExpression.VariableType)) { LLVMValueRef leftValue = LLVM.BuildLoad(Builder, leftExpression.LLVMPtrValueRef, "leftValue"); LLVMValueRef rightValue = LLVM.BuildLoad(Builder, rightExpression.LLVMPtrValueRef, "rightValue"); LLVMRegister ret = null; //will return null if this is not an arithmetic operation ret = GenerateNativeArithmeticOperation(context, leftValue, rightValue, operatorName); if (ret == null) { //will return null if this is not a comparison operation ret = GenerateNativeComparison(context, leftValue, rightValue, operatorName); } if (ret == null) { string errorMessage = String.Format("The native class {0} does not support operator {1}", expressionClassName, operatorName); Status.AddError(new CompilerError(FileName, context.Start.Line, context.Start.Column, errorMessage)); //just assume this is operation returns a constant int to avoid stalling the compilation ret = GetConstantIntRegisterOfClepsType(context, LLVM.Int32TypeInContext(Context), 7, "int32" /* friendly type name */); } return(ret); } else { if (!ClassManager.LoadedClassesAndMembers[expressionClassName].DoesClassContainMember(operatorName, false /* search member types only */)) { string errorMessage = String.Format("The class {0} does not have a operator {1} defined", expressionClassName, operatorName); Status.AddError(new CompilerError(FileName, context.Start.Line, context.Start.Column, errorMessage)); //just assume this is operation returns a constant int to avoid stalling the compilation LLVMRegister ret = GetConstantIntRegisterOfClepsType(context, LLVM.Int32TypeInContext(Context), 7, "int32" /* friendly type name */); return(ret); } ClepsClass variableClass = ClassManager.LoadedClassesAndMembers[expressionClassName]; if (!variableClass.MemberMethods.ContainsKey(operatorName)) { string errorMessage = String.Format("The class {0} does not have operator {1} defined", expressionClassName, operatorName); Status.AddError(new CompilerError(FileName, context.Start.Line, context.Start.Column, errorMessage)); //just assume this is operation returns a constant int to avoid stalling the compilation LLVMRegister ret = GetConstantIntRegisterOfClepsType(context, LLVM.Int32TypeInContext(Context), 7, "int32" /* friendly type name */); return(ret); } ClepsType assignmentFunctionToCall = variableClass.MemberMethods[operatorName]; if (assignmentFunctionToCall.FunctionParameters.Count != 3 && assignmentFunctionToCall.FunctionParameters[1] != leftExpression.VariableType && assignmentFunctionToCall.FunctionParameters[2] != rightExpression.VariableType) { string errorMessage = String.Format("The class {0} does not have an operator {1} defined that takes parameter ({2}, {3})", expressionClassName, operatorName, leftExpression.VariableType, rightExpression.VariableType); Status.AddError(new CompilerError(FileName, context.Start.Line, context.Start.Column, errorMessage)); //just assume this is operation returns a constant int to avoid stalling the compilation LLVMRegister ret = GetConstantIntRegisterOfClepsType(context, LLVM.Int32TypeInContext(Context), 7, "int32" /* friendly type name */); return(ret); } string assignmentFunctionNameToCall = String.Format("{0}.{1}", expressionClassName, operatorName); LLVMValueRef llvmAssignmentFunction = LLVM.GetNamedFunction(Module, assignmentFunctionNameToCall); LLVMValueRef operatorArg = LLVM.BuildLoad(Builder, rightExpression.LLVMPtrValueRef, "operatorArg"); LLVMValueRef[] parameters = new LLVMValueRef[] { leftExpression.LLVMPtrValueRef, operatorArg }; LLVMValueRef operatorReturnRegister = LLVM.BuildCall(Builder, llvmAssignmentFunction, parameters, "operator" + operatorName + "Call"); LLVMValueRef operatorReturnPtr = LLVM.BuildAlloca(Builder, LLVM.TypeOf(operatorReturnRegister), "operatorReturnPtr"); LLVM.BuildStore(Builder, operatorReturnRegister, operatorReturnPtr); ClepsType returnType = assignmentFunctionToCall.FunctionReturnType; LLVMRegister operatorReturn = new LLVMRegister(returnType, operatorReturnPtr); return(operatorReturn); } }
private IValue doFunctionCall(ParserRuleContext context, string targetFunctionName, List <IValue> parameters, IValue target, ClepsType targetType, bool allowVoidReturn) { IValue dereferencedTarget = target == null? null : GetDereferencedRegisterOrNull(target); BasicClepsType dereferencedType = target == null? targetType as BasicClepsType : dereferencedTarget.ExpressionType as BasicClepsType; if (dereferencedType == null) { string errorMessage = String.Format("Could not dereference expression on type {0}", targetType.GetClepsTypeString()); Status.AddError(new CompilerError(FileName, context.Start.Line, context.Start.Column, errorMessage)); //just return something to avoid stalling return(CodeGenerator.CreateByte(0)); } ClepsClass targetClepsClass = ClassManager.GetClass(dereferencedType.GetClepsTypeString()); List <ClepsVariable> functionOverloads; bool isStatic; if (targetClepsClass.StaticMemberMethods.ContainsKey(targetFunctionName)) { isStatic = true; functionOverloads = targetClepsClass.StaticMemberMethods[targetFunctionName]; } else if (target != null && targetClepsClass.MemberMethods.ContainsKey(targetFunctionName)) { isStatic = false; functionOverloads = targetClepsClass.MemberMethods[targetFunctionName]; } else { string errorMessage = String.Format("Class {0} does not contain a {1}static function called {2}.", targetClepsClass.FullyQualifiedName, target == null? "" : "member or ", targetFunctionName); Status.AddError(new CompilerError(FileName, context.Start.Line, context.Start.Column, errorMessage)); //Just return something to avoid stalling compilation return(CodeGenerator.CreateByte(0)); } int matchedPosition; string fnMatchErrorMessage; if (!FunctionOverloadManager.FindMatchingFunctionType(TypeManager, functionOverloads, parameters, out matchedPosition, out fnMatchErrorMessage)) { Status.AddError(new CompilerError(FileName, context.Start.Line, context.Start.Column, fnMatchErrorMessage)); //Just return something to avoid stalling compilation return(CodeGenerator.CreateByte(0)); } FunctionClepsType chosenFunctionType = functionOverloads[matchedPosition].VariableType as FunctionClepsType; if (!allowVoidReturn && chosenFunctionType.ReturnType == VoidClepsType.GetVoidType()) { string errorMessage = String.Format("Function {0} does not return a value", targetFunctionName); Status.AddError(new CompilerError(FileName, context.Start.Line, context.Start.Column, errorMessage)); //Just return something to avoid stalling compilation return(CodeGenerator.CreateByte(0)); } IValue returnValue = CodeGenerator.GetFunctionCallReturnValue(isStatic? null : dereferencedTarget, dereferencedType, targetFunctionName, chosenFunctionType, parameters); return(returnValue); }
public void SetClassBodyAndCreateConstructor(ClepsClass clepsClass) { ClassesLoaded[clepsClass.FullyQualifiedName] = clepsClass; }
public void SetClassDefinition(ClepsClass clepsClass) { LoadedClasses.Add(clepsClass.FullyQualifiedName, clepsClass); }