Skip to content

Commit

Permalink
FINALLY, (sometimes) working classes
Browse files Browse the repository at this point in the history
  • Loading branch information
vyPal committed Nov 23, 2023
1 parent e9b2350 commit ee7c18c
Show file tree
Hide file tree
Showing 9 changed files with 534 additions and 52 deletions.
17 changes: 14 additions & 3 deletions example.cffc
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
for (var x:int = 0; x < 10; x = x + 1) {
print x;
}
class Bek {
a:int;

Bek() {
this.a = 1;
}

func sob() {
print this.a;
}
}

var lol: Bek = new Bek();
lol.sob();
112 changes: 112 additions & 0 deletions src/compiler/classes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package compiler

import (
"fmt"

"github.com/llir/llvm/ir"
"github.com/llir/llvm/ir/types"
"github.com/llir/llvm/ir/value"
)

type Class struct {
Stmt
Name string
Constructor Method
Fields []Field
Methods []Method
}

type Field struct {
Name string
Type types.Type
Private bool
Index int
}

type Method struct {
Name string
Params []*ir.Param
ReturnType types.Type
Body []Stmt
Private bool
}

func (ctx *Context) compileClassDeclaration(c *Class) {
classType := types.NewStruct()
for _, field := range c.Fields {
classType.Fields = append(classType.Fields, field.Type)
}
ctx.Compiler.StructFields[c.Name] = c.Fields
fmt.Println(c.Constructor.Body[0])
ctx.Module.NewTypeDef(c.Name, classType)
if c.Constructor.Name != "" {
fmt.Println("Declaring constructor " + c.Constructor.Name)
constructor := ctx.compileMethodDeclaration(c.Constructor, c)
// Add constructor to the symbol table
ctx.Compiler.SymbolTable[c.Name] = constructor
}
for _, m := range c.Methods {
fmt.Println("Declaring method " + m.Name)
ctx.Compiler.SymbolTable[c.Name+"."+m.Name] = ctx.compileMethodDeclaration(m, c)
}
}

func (ctx *Context) compileMethodDeclaration(m Method, c *Class) *ir.Func {
params := m.Params
var typeDef types.Type
for _, t := range ctx.Module.TypeDefs {
if t.Name() == c.Name {
typeDef = t
break
}
}

if typeDef == nil {
panic("type not found")
}
params = append(params, ir.NewParam("this", types.NewPointer(typeDef)))
f := ctx.Module.NewFunc(m.Name, m.ReturnType)
f.Params = params
block := f.NewBlock("entry")
classctx := ctx.NewContext(block)
for _, stmt := range m.Body {
classctx.compileStmt(stmt)
}
if classctx.Term == nil {
if m.ReturnType.Equal(types.Void) {
classctx.NewRet(nil)
} else {
panic(fmt.Errorf("function `%s` does not return a value", m.Name))
}
}

return f
}

func (ctx *Context) compileClassMethod(c SClassMethod) {
// Get the class instance
instance := ctx.lookupVariable(c.InstanceName)

var classType types.Type
for _, t := range ctx.Module.TypeDefs {
if t.Equal(instance.Type().(*types.PointerType).ElemType) {
classType = t
break
}
}
if classType == nil {
panic(fmt.Errorf("type `%s` not found", instance.Type().String()))
}
// Get the method
method := ctx.Compiler.SymbolTable[instance.Type().(*types.PointerType).ElemType.Name()+"."+c.MethodName].(*ir.Func)
if method == nil {
panic(fmt.Errorf("method '%s.%s' not found", instance.Type().(*types.PointerType).ElemType.Name(), c.MethodName))
}
// Get the function arguments
var args []value.Value
for _, arg := range c.Args {
args = append(args, ctx.compileExpr(arg))
}
// Call the function
ctx.NewCall(method, append([]value.Value{instance}, args...)...)
}
1 change: 1 addition & 0 deletions src/compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ type Compiler struct {
SymbolTable map[string]value.Value
Context *Context
AST []Stmt
StructFields map[string][]Field
VarsCanBeNumbers bool
}

Expand Down
141 changes: 127 additions & 14 deletions src/compiler/expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,83 @@ func (ctx *Context) compileExpr(e Expr) value.Value {
return ctx.compileConst(e)
case EVar:
v := ctx.lookupVariable(e.Name)
if p, ok := v.Type().(*types.PointerType); ok {
v = ctx.Block.NewLoad(p.ElemType, v)
}
return v
case EField:
structVal := ctx.compileExpr(e.Struct)
//fieldName := ctx.compileExpr(e.Name)
var field Field
elemtypename := structVal.Type().(*types.PointerType).ElemType.Name()
for f := range ctx.Compiler.StructFields[elemtypename] {
if ctx.Compiler.StructFields[elemtypename][f].Name == e.Name.(EVar).Name {
field = ctx.Compiler.StructFields[elemtypename][f]
break
}
}
fieldPtr := ctx.Block.NewGetElementPtr(field.Type, structVal, constant.NewInt(types.I32, int64(field.Index)))
return ctx.Block.NewLoad(field.Type, fieldPtr)
case EAssign:
v := ctx.compileExpr(e.Value)
ctx.vars[e.Name] = v
return v
switch name := e.Name.(type) {
case EVar:
v := ctx.compileExpr(e.Value)
if p, ok := v.Type().(*types.PointerType); ok {
v = ctx.Block.NewLoad(p.ElemType, v)
}
ctx.vars[name.Name] = v
return v
case EField:
structVal := ctx.compileExpr(name.Struct)
//fieldName := ctx.compileExpr(e.Name)

var field Field
elemtypename := structVal.Type().(*types.PointerType).ElemType.Name()
for f := range ctx.Compiler.StructFields[elemtypename] {
if ctx.Compiler.StructFields[elemtypename][f].Name == name.Name.(EVar).Name {
field = ctx.Compiler.StructFields[elemtypename][f]
break
}
}

// Ensure structVal is a pointer
if _, ok := structVal.Type().(*types.PointerType); !ok {
structVal = ctx.Block.NewLoad(types.NewPointer(structVal.Type()), structVal)
}

fieldPtr := ctx.Block.NewGetElementPtr(structVal.Type().(*types.PointerType).ElemType, structVal, constant.NewInt(types.I32, int64(field.Index)))

// Ensure value is of correct type
if fieldPtr.Type().(*types.PointerType).ElemType != field.Type {
panic(fmt.Errorf("field type mismatch: expected %s, got %s", field.Type, fieldPtr.Type().(*types.PointerType).ElemType))
}

return ctx.Block.NewLoad(fieldPtr.Type().(*types.PointerType).ElemType, fieldPtr)
default:
panic(fmt.Errorf("unknown assignment type: %T", name))
}
case EClassConstructor:
// Allocate memory for the struct
var structType types.Type
for _, t := range ctx.Module.TypeDefs {
if t.Name() == e.Name {
structType = t
break
}
}
if structType == nil {
panic(fmt.Sprintf("type `%s` not found", structType))
}
fmt.Printf("Type: %T\n", structType)
structVal := ctx.Block.NewAlloca(structType)
// Call the constructor
constructor := ctx.Compiler.SymbolTable[e.Name]
if constructor == nil {
panic(fmt.Sprintf("constructor for type `%s` not found", e.Name))
}
args := []value.Value{structVal}
for _, arg := range e.Args {
args = append(args, ctx.compileExpr(arg))
}
ctx.Block.NewCall(constructor, args...)
return structVal
case ECall:
return ctx.compileFunctionCallExpr(e)
case EAdd:
Expand Down Expand Up @@ -136,16 +205,56 @@ func (ctx *Context) compileStmt(stmt Stmt) {
if ctx.Block == nil {
panic("cannot declare variable outside of a function")
}
v := ctx.NewAlloca(s.Typ)
value := ctx.compileExpr(s.Expr)
if value.Type().Equal(types.NewPointer(s.Typ)) {
value = ctx.NewLoad(s.Typ, value)
if s.Typ == nil && s.CustomTypeName != "" {
for _, t := range ctx.Module.TypeDefs {
if t.Name() == s.CustomTypeName {
s.Typ = types.NewPointer(t)
break
}
}
if s.Typ == nil {
panic(fmt.Sprintf("type `%s` not found", s.CustomTypeName))
}
}
ctx.NewStore(value, v)
ctx.vars[s.Name] = v
value := ctx.compileExpr(s.Expr)
ctx.vars[s.Name] = value
case *SAssign:
v := ctx.lookupVariable(s.Name)
ctx.NewStore(ctx.compileExpr(s.Expr), v)
switch name := s.Name.(type) {
case EVar:
v := ctx.compileExpr(s.Expr)
if p, ok := v.Type().(*types.PointerType); ok {
v = ctx.Block.NewLoad(p.ElemType, v)
}
ctx.vars[name.Name] = v
case EField:
structVal := ctx.compileExpr(name.Struct)
value := ctx.compileExpr(s.Expr)
fmt.Println(structVal, value)

var field Field
fmt.Println(structVal.Type().(*types.PointerType).ElemType.Name())
elemtypename := structVal.Type().(*types.PointerType).ElemType.Name()
for f := range ctx.Compiler.StructFields[elemtypename] {
if ctx.Compiler.StructFields[elemtypename][f].Name == name.Name.(EVar).Name {
field = ctx.Compiler.StructFields[elemtypename][f]
break
}
}
fmt.Println(field)
fieldPtr := ctx.Block.NewGetElementPtr(field.Type, structVal, constant.NewInt(types.I32, int64(field.Index)))

// Ensure value is of correct type
if ctx != nil && ctx.Block != nil && value != nil && field.Type != nil {
value = ctx.Block.NewBitCast(value, field.Type)
} else {
fmt.Println("One of the variables is not initialized")
}
fmt.Println(fieldPtr)

ctx.Block.NewStore(value, fieldPtr)
default:
panic(fmt.Errorf("unknown assignment type: %T", name))
}
case *SPrint:
ctx.compilePrintCall(*s)
case *SSleep:
Expand All @@ -154,6 +263,8 @@ func (ctx *Context) compileStmt(stmt Stmt) {
ctx.compileFunctionDecl(*s)
case *SFuncCall:
ctx.compileFunctionCall(*s)
case *SClassMethod:
ctx.compileClassMethod(*s)
case *SRet:
ctx.NewRet(ctx.compileExpr(s.Val))
case *SIf:
Expand Down Expand Up @@ -212,6 +323,8 @@ func (ctx *Context) compileStmt(stmt Stmt) {
}
loopCtx.NewCondBr(loopCtx.compileExpr(s.Cond), loopCtx.Block, leaveB)
ctx.Compiler.Context.Block = leaveB
case *Class:
ctx.compileClassDeclaration(s)
case *SBreak:
ctx.NewBr(ctx.leaveBlock)
default:
Expand Down
32 changes: 27 additions & 5 deletions src/compiler/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,30 @@ type EVar struct {
Expr
Name string
}
type EClassConstructor struct {
Expr
Name string
Args []Expr
}
type SClassMethod struct {
Stmt
InstanceName string
MethodName string
Args []Expr
}
type EClassField struct {
Expr
ClassName string
FieldName string
}
type EField struct {
Expr
Struct Expr
Name Expr
}
type EAssign struct {
Expr
Name string
Name Expr
Value Expr
}
type ECall struct {
Expand Down Expand Up @@ -122,13 +143,14 @@ type ENot struct {
type Stmt interface{ isStmt() Stmt }
type SDefine struct {
Stmt
Name string
Typ types.Type
Expr Expr
Name string
Typ types.Type
CustomTypeName string
Expr Expr
}
type SAssign struct {
Stmt
Name string
Name Expr
Expr Expr
}
type SPrint struct {
Expand Down
2 changes: 1 addition & 1 deletion src/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func main() {
p := parser.Parser{Tokens: Tokens}
p.Parse()

c := compiler.Compiler{Module: mod, SymbolTable: make(map[string]value.Value), AST: p.AST, VarsCanBeNumbers: *numbers_are_variables}
c := compiler.Compiler{Module: mod, SymbolTable: make(map[string]value.Value), AST: p.AST, VarsCanBeNumbers: *numbers_are_variables, StructFields: make(map[string][]compiler.Field)}
c.Compile()

tmpDir := "tmp_compile"
Expand Down
Loading

0 comments on commit ee7c18c

Please sign in to comment.