func build(files []string, outputFile string, cg string, outputType LLVMCodegen.OutputType, optLevel int) { constructedModules, _ := parseFiles(files) // resolve log.Timed("resolve phase", "", func() { for _, module := range constructedModules { res := &parser.Resolver{Module: module} vis := parser.NewASTVisitor(res) vis.VisitModule(module) } }) // type inference log.Timed("inference phase", "", func() { for _, module := range constructedModules { inf := &parser.TypeInferer{Module: module} inf.Infer() // Dump AST log.Debugln("main", "AST of module `%s`:", module.Name) for _, node := range module.Nodes { log.Debugln("main", "%s", node.String()) } log.Debugln("main", "") } }) // semantic analysis log.Timed("semantic analysis phase", "", func() { for _, module := range constructedModules { sem := semantic.NewSemanticAnalyzer(module, *buildOwnership, *ignoreUnused) vis := parser.NewASTVisitor(sem) vis.VisitModule(module) sem.Finalize() } }) // codegen if cg != "none" { var gen codegen.Codegen switch cg { case "llvm": gen = &LLVMCodegen.Codegen{ OutputName: outputFile, OutputType: outputType, OptLevel: optLevel, } default: log.Error("main", util.Red("error: ")+"Invalid backend choice `"+cg+"`") os.Exit(1) } log.Timed("codegen phase", "", func() { gen.Generate(constructedModules) }) } }
func (v *StructLiteralNode) construct(c *Constructor) Expr { res := &StructLiteral{} if v.Name != nil { res.Type = &UnresolvedType{Name: toUnresolvedName(v.Name)} } res.Values = make(map[string]Expr) for idx, member := range v.Members { res.Values[member.Value] = c.constructExpr(v.Values[idx]) } if v.Name == nil { return res } else if typ := c.nameMap.TypeOfNameNode(v.Name); typ == NODE_ENUM_MEMBER { enum := &EnumLiteral{} enum.Member = v.Name.Name.Value enum.Type = &UnresolvedType{Name: toParentName(v.Name)} enum.StructLiteral = res enum.setPos(v.Where().Start()) return enum } else { log.Debugln("constructor", "`%s` was a `%s`", v.Name.Name.Value, typ) c.errSpan(v.Name.Name.Where, "Name `%s` is not a struct or a enum member", v.Name.Name.Value) return nil } }
func runtimeMustLoadType(mod *Module, name string) Type { log.Debugln("runtime", "Loading runtime type: %s", name) ident := mod.ModScope.GetIdent(UnresolvedName{Name: name}) if ident.Type != IDENT_TYPE { panic("INTERNAL ERROR: Type not defined in runtime: " + name) } return ident.Value.(Type) }
func ExtractTypeVariable(pattern Type, value Type) map[string]Type { /* Pointer($T), Pointer(int) -> {$T: int} Arbitrary depth type => Stack containing breadth first traversal */ res := make(map[string]Type) var ( ps []Type vs []Type ) ps = append(ps, pattern) vs = append(vs, value) for i := 0; i < len(ps); i++ { ppart := ps[i] vpart := vs[i] log.Debugln("resovle", "\nP = `%s`, V = `%s`", ppart.TypeName(), vpart.TypeName()) ps = AddChildren(ppart, ps) vs = AddChildren(vpart, vs) if vari, ok := ppart.(ParameterType); ok { log.Debugln("resolve", "P was variable (Name: %s)", vari.Name) res[vari.Name] = vpart continue } switch ppart.(type) { case PrimitiveType, *NamedType: if !ppart.Equals(vpart) { log.Errorln("resolve", "%s != %s", ppart.TypeName(), vpart.TypeName()) panic("Part of type did not match pattern") } default: if reflect.TypeOf(ppart) != reflect.TypeOf(vpart) { log.Errorln("resolve", "%T != %T", ppart, vpart) panic("Part of type did not match pattern") } } } return res }
func (v *ModuleLookup) Dump(i int) { if v.Name != "" { log.Debug("main", "%s", strings.Repeat(" ", i)) log.Debugln("main", "%s", v.Name) } for _, child := range v.Children { child.Dump(i + 1) } }
func (v *Codegen) genAccessGEP(n parser.Expr) llvm.Value { switch access := n.(type) { case *parser.VariableAccessExpr: varType := v.getVariable(access.Variable) log.Debugln("codegen", "%v => %v", access.Variable, varType) if varType.IsNil() { panic("varType was nil") } gep := v.builder().CreateGEP(varType, []llvm.Value{llvm.ConstInt(llvm.Int32Type(), 0, false)}, "") if _, ok := access.GetType().(parser.MutableReferenceType); ok { return v.builder().CreateLoad(gep, "") } if _, ok := access.GetType().(parser.ConstantReferenceType); ok { return v.builder().CreateLoad(gep, "") } return gep case *parser.StructAccessExpr: gep := v.genAccessGEP(access.Struct) typ := access.Struct.GetType().ActualType() index := typ.(parser.StructType).VariableIndex(access.Variable) return v.builder().CreateStructGEP(gep, index, "") case *parser.ArrayAccessExpr: gep := v.genAccessGEP(access.Array) subscriptExpr := v.genExpr(access.Subscript) v.genBoundsCheck(v.builder().CreateLoad(v.builder().CreateStructGEP(gep, 0, ""), ""), subscriptExpr, access.Subscript.GetType()) gep = v.builder().CreateStructGEP(gep, 1, "") load := v.builder().CreateLoad(gep, "") gepIndexes := []llvm.Value{subscriptExpr} return v.builder().CreateGEP(load, gepIndexes, "") case *parser.TupleAccessExpr: gep := v.genAccessGEP(access.Tuple) // TODO: Check overflow return v.builder().CreateStructGEP(gep, int(access.Index), "") case *parser.DerefAccessExpr: return v.genExpr(access.Expr) default: panic("unhandled access type") } }
func (v *Scope) Dump(depth int) { indent := strings.Repeat(" ", depth) if depth == 0 { log.Debug("parser", indent) log.Debugln("parser", "This scope:") } for name, ident := range v.Idents { log.Debug("parser", indent) log.Debugln("parser", " %s (%s)", name, ident.Type) } if v.Outer != nil { log.Debug("parser", indent) log.Debugln("parser", "Parent scope:") v.Outer.Dump(depth + 1) } }
func (v *CallExprNode) construct(c *Constructor) Expr { // TODO: when we allow function types, allow all access forms (eg. `thing[0]()``) if van, ok := v.Function.(*VariableAccessNode); ok { typ := c.nameMap.TypeOfNameNode(van.Name) if typ == NODE_FUNCTION { res := &CallExpr{ Arguments: c.constructExprs(v.Arguments), functionSource: c.constructExpr(v.Function), } res.setPos(v.Where().Start()) return res } else if typ == NODE_ENUM_MEMBER { res := &EnumLiteral{ Member: van.Name.Name.Value, Type: &UnresolvedType{Name: toParentName(van.Name)}, TupleLiteral: &TupleLiteral{Members: c.constructExprs(v.Arguments)}, } res.setPos(v.Where().Start()) return res } else if typ.IsType() { if len(v.Arguments) > 1 { c.errSpan(v.Where(), "Cast cannot recieve more that one argument") } res := &CastExpr{ Type: c.constructType(&TypeReferenceNode{Reference: van.Name}), Expr: c.constructExpr(v.Arguments[0]), } res.setPos(v.Where().Start()) return res } else { log.Debugln("constructor", "`%s` was a `%s`", van.Name.Name.Value, typ) c.errSpan(van.Name.Name.Where, "Name `%s` is not a function or a enum member", van.Name.Name.Value) return nil } } else if sae, ok := v.Function.(*StructAccessNode); ok { res := &CallExpr{ Arguments: c.constructExprs(v.Arguments), functionSource: c.constructExpr(v.Function), } res.ReceiverAccess = sae.construct(c).(*StructAccessExpr).Struct res.setPos(v.Where().Start()) return res } else { c.err(van.Name.Name.Where, "Can't call function on this") return nil } }
func (v *Codegen) typeToLLVMType(typ ast.Type, gcon *ast.GenericContext) llvm.Type { switch typ := typ.(type) { case ast.PrimitiveType: return v.primitiveTypeToLLVMType(typ) case ast.FunctionType: return v.functionTypeToLLVMType(typ, true, gcon) case ast.StructType: return v.structTypeToLLVMType(typ, gcon) case ast.PointerType: return llvm.PointerType(v.typeRefToLLVMTypeWithOuter(typ.Addressee, gcon), 0) case ast.ArrayType: return v.arrayTypeToLLVMType(typ, gcon) case ast.TupleType: return v.tupleTypeToLLVMType(typ, gcon) case ast.EnumType: return v.enumTypeToLLVMType(typ, gcon) case ast.ReferenceType: return llvm.PointerType(v.typeRefToLLVMTypeWithOuter(typ.Referrer, gcon), 0) case *ast.NamedType: switch typ.Type.(type) { case ast.StructType, ast.EnumType: // If something seems wrong with the code and thie problems seems to come from here, // make sure the type doesn't need generics arguments as well. // This here ignores them. name := ast.TypeReferenceMangledName(ast.MANGLE_ARK_UNSTABLE, &ast.TypeReference{BaseType: typ}, gcon) v.addNamedType(typ, name, gcon) lt := v.namedTypeLookup[name] return lt default: return v.typeToLLVMType(typ.Type, gcon) } case *ast.SubstitutionType: if gcon == nil { panic("gcon == nil when getting substitution type") } if gcon.GetSubstitutionType(typ) == nil { panic("missing generic map entry for type " + typ.TypeName() + " " + fmt.Sprintf("(%p)", typ)) } return v.typeRefToLLVMTypeWithOuter(gcon.GetSubstitutionType(typ), gcon) default: log.Debugln("codegen", "Type was %s (%s)", typ.TypeName(), reflect.TypeOf(typ)) panic("Unimplemented type category in LLVM codegen") } }
func (v *Codegen) typeToLLVMType(typ parser.Type) llvm.Type { switch typ.(type) { case parser.PrimitiveType: return v.primitiveTypeToLLVMType(typ.(parser.PrimitiveType)) case *parser.StructType: return v.structTypeToLLVMType(typ.(*parser.StructType)) case parser.PointerType: return llvm.PointerType(v.typeToLLVMType(typ.(parser.PointerType).Addressee), 0) case parser.ArrayType: return v.arrayTypeToLLVMType(typ.(parser.ArrayType)) case *parser.TupleType: return v.tupleTypeToLLVMType(typ.(*parser.TupleType)) case *parser.EnumType: return v.enumTypeToLLVMType(typ.(*parser.EnumType)) case *parser.NamedType: return v.typeToLLVMType(typ.(*parser.NamedType).Type) default: log.Debugln("codegen", "Type was %s", typ) panic("Unimplemented type category in LLVM codegen") } }
func (v *Codegen) typeToLLVMType(typ parser.Type) llvm.Type { switch typ := typ.(type) { case parser.PrimitiveType: return v.primitiveTypeToLLVMType(typ) case parser.FunctionType: return v.functionTypeToLLVMType(typ, true) case parser.StructType: return v.structTypeToLLVMType(typ) case parser.PointerType: return llvm.PointerType(v.typeToLLVMType(typ.Addressee), 0) case parser.ArrayType: return v.arrayTypeToLLVMType(typ) case parser.TupleType: return v.tupleTypeToLLVMType(typ) case parser.EnumType: return v.enumTypeToLLVMType(typ) case *parser.NamedType: nt := typ switch nt.Type.(type) { case parser.StructType, parser.EnumType: v.addNamedType(nt) lt := v.namedTypeLookup[nt.MangledName(parser.MANGLE_ARK_UNSTABLE)] return lt default: return v.typeToLLVMType(nt.Type) } case parser.MutableReferenceType: return llvm.PointerType(v.typeToLLVMType(typ.Referrer), 0) case parser.ConstantReferenceType: return llvm.PointerType(v.typeToLLVMType(typ.Referrer), 0) default: log.Debugln("codegen", "Type was %s (%s)", typ.TypeName(), reflect.TypeOf(typ)) panic("Unimplemented type category in LLVM codegen") } }
func build(files []string, outputFile string, cg string, outputType LLVMCodegen.OutputType, optLevel int) { constructedModules, moduleLookup := parseFiles(files) // resolve hasMainFunc := false log.Timed("resolve phase", "", func() { for _, module := range constructedModules { parser.Resolve(module, moduleLookup) // Use module scope to check for main function mainIdent := module.ModScope.GetIdent(parser.UnresolvedName{Name: "main"}) if mainIdent != nil && mainIdent.Type == parser.IDENT_FUNCTION && mainIdent.Public { hasMainFunc = true } } }) // and here we check if we should // bother continuing any further... if !hasMainFunc { log.Error("main", util.Red("error: ")+"main function not found\n") os.Exit(1) } // type inference log.Timed("inference phase", "", func() { for _, module := range constructedModules { for _, submod := range module.Parts { inf := &parser.TypeInferer{Submodule: submod} inf.Infer() // Dump AST log.Debugln("main", "AST of submodule `%s/%s`:", module.Name, submod.File.Name) for _, node := range submod.Nodes { log.Debugln("main", "%s", node.String()) } log.Debugln("main", "") } } }) // semantic analysis log.Timed("semantic analysis phase", "", func() { for _, module := range constructedModules { for _, submod := range module.Parts { sem := semantic.NewSemanticAnalyzer(submod, *buildOwnership, *ignoreUnused) vis := parser.NewASTVisitor(sem) vis.VisitSubmodule(submod) sem.Finalize() } } }) // codegen if cg != "none" { var gen codegen.Codegen switch cg { case "llvm": gen = &LLVMCodegen.Codegen{ OutputName: outputFile, OutputType: outputType, OptLevel: optLevel, } default: log.Error("main", util.Red("error: ")+"Invalid backend choice `"+cg+"`") os.Exit(1) } log.Timed("codegen phase", "", func() { gen.Generate(constructedModules) }) } }
func (v *parser) dumpRules() { log.Debugln("parser", strings.Join(v.ruleStack, " / ")) }
func (v *Context) Build(output string, outputType codegen.OutputType, usedCodegen string, optLevel int) { // Start by loading the runtime runtimeModule := LoadRuntime() // Parse the passed files v.parseFiles() // resolve hasMainFunc := false log.Timed("resolve phase", "", func() { for _, module := range v.modules { ast.Resolve(module, v.moduleLookup) // Use module scope to check for main function mainIdent := module.ModScope.GetIdent(ast.UnresolvedName{Name: "main"}) if mainIdent != nil && mainIdent.Type == ast.IDENT_FUNCTION && mainIdent.Public { hasMainFunc = true } } }) // and here we check if we should // bother continuing any further... if !hasMainFunc { log.Error("main", util.Red("error: ")+"main function not found\n") os.Exit(1) } // type inference log.Timed("inference phase", "", func() { for _, module := range v.modules { for _, submod := range module.Parts { ast.Infer(submod) // Dump AST log.Debugln("main", "AST of submodule `%s/%s`:", module.Name, submod.File.Name) for _, node := range submod.Nodes { log.Debugln("main", "%s", node.String()) } log.Debugln("main", "") } } }) // semantic analysis log.Timed("semantic analysis phase", "", func() { for _, module := range v.modules { semantic.SemCheck(module, *ignoreUnused) } }) // codegen if usedCodegen != "none" { var gen codegen.Codegen switch usedCodegen { case "llvm": gen = &LLVMCodegen.Codegen{ OutputName: output, OutputType: outputType, OptLevel: optLevel, } default: log.Error("main", util.Red("error: ")+"Invalid backend choice `"+usedCodegen+"`") os.Exit(1) } log.Timed("codegen phase", "", func() { mods := v.modules if runtimeModule != nil { mods = append(mods, runtimeModule) } gen.Generate(mods) }) } }