feat: add method call support and analyzeFull
- Add analyzeFull() to return Sema context with method table - Improve method call desugaring: obj.method() → Type_method(obj) - Search methodTable by method name when type inference fails - Add methods.bux example demonstrating struct with extend blocks - Use analyzeFull in cli.nim for proper method resolution
This commit is contained in:
@@ -0,0 +1,38 @@
|
|||||||
|
// Methods - Struct with methods using extend
|
||||||
|
extern func Std_Io_PrintLine(s: String);
|
||||||
|
extern func Std_Io_PrintInt(n: int);
|
||||||
|
|
||||||
|
struct Rectangle {
|
||||||
|
width: int;
|
||||||
|
height: int;
|
||||||
|
}
|
||||||
|
|
||||||
|
extend Rectangle {
|
||||||
|
func Area(self: Rectangle) -> int {
|
||||||
|
return self.width * self.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
func Perimeter(self: Rectangle) -> int {
|
||||||
|
return 2 * (self.width + self.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Main() -> int {
|
||||||
|
let rect: Rectangle = Rectangle { width: 10, height: 5 };
|
||||||
|
|
||||||
|
Std_Io_PrintLine("Rectangle:");
|
||||||
|
Std_Io_PrintLine("Width = ");
|
||||||
|
Std_Io_PrintInt(rect.width);
|
||||||
|
Std_Io_PrintLine("");
|
||||||
|
Std_Io_PrintLine("Height = ");
|
||||||
|
Std_Io_PrintInt(rect.height);
|
||||||
|
Std_Io_PrintLine("");
|
||||||
|
Std_Io_PrintLine("Area = ");
|
||||||
|
Std_Io_PrintInt(rect.Area());
|
||||||
|
Std_Io_PrintLine("");
|
||||||
|
Std_Io_PrintLine("Perimeter = ");
|
||||||
|
Std_Io_PrintInt(rect.Perimeter());
|
||||||
|
Std_Io_PrintLine("");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
+2
-4
@@ -226,7 +226,7 @@ proc cmdBuild*(args: seq[string], opts: GlobalOptions): int =
|
|||||||
for d in parseRes.diagnostics:
|
for d in parseRes.diagnostics:
|
||||||
echo &"error: {d.message} at {d.loc}"
|
echo &"error: {d.message} at {d.loc}"
|
||||||
return 1
|
return 1
|
||||||
let semaRes = analyze(parseRes.module)
|
let (semaRes, semaCtx) = analyzeFull(parseRes.module)
|
||||||
if semaRes.hasErrors:
|
if semaRes.hasErrors:
|
||||||
printError(&"type errors in {path}", useColor)
|
printError(&"type errors in {path}", useColor)
|
||||||
for d in semaRes.diagnostics:
|
for d in semaRes.diagnostics:
|
||||||
@@ -235,9 +235,7 @@ proc cmdBuild*(args: seq[string], opts: GlobalOptions): int =
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
# Lower to HIR
|
# Lower to HIR
|
||||||
var s = Sema(module: parseRes.module, globalScope: newScope())
|
let hirModule = lowerModule(parseRes.module, semaCtx)
|
||||||
s.collectGlobals()
|
|
||||||
let hirModule = lowerModule(parseRes.module, s)
|
|
||||||
|
|
||||||
# Generate C code
|
# Generate C code
|
||||||
var cbe = initCBackend()
|
var cbe = initCBackend()
|
||||||
|
|||||||
+13
-8
@@ -148,22 +148,27 @@ proc lowerExpr(ctx: var LowerCtx, expr: Expr): HirNode =
|
|||||||
of ekCall:
|
of ekCall:
|
||||||
# Method call desugaring: obj.method(args) → Type_method(obj, args)
|
# Method call desugaring: obj.method(args) → Type_method(obj, args)
|
||||||
if expr.exprCallCallee.kind == ekField:
|
if expr.exprCallCallee.kind == ekField:
|
||||||
let recvType = ctx.resolveExprType(expr.exprCallCallee.exprFieldObj)
|
|
||||||
let methodName = expr.exprCallCallee.exprFieldName
|
let methodName = expr.exprCallCallee.exprFieldName
|
||||||
var typeName = ""
|
|
||||||
if recvType.kind == tkNamed: typeName = recvType.name
|
# Try to find the method in methodTable
|
||||||
elif recvType.isPointer and recvType.inner.len > 0 and recvType.inner[0].kind == tkNamed:
|
for typeName, methods in ctx.methodTable:
|
||||||
typeName = recvType.inner[0].name
|
for minfo in methods:
|
||||||
if typeName != "" and ctx.methodTable.hasKey(typeName):
|
|
||||||
for minfo in ctx.methodTable[typeName]:
|
|
||||||
if minfo.name == methodName:
|
if minfo.name == methodName:
|
||||||
# Desugar: obj.method(args) → Type_method(&obj, args)
|
# Found the method - desugar to Type_method(receiver, args)
|
||||||
let mangledName = typeName & "_" & methodName
|
let mangledName = typeName & "_" & methodName
|
||||||
var args: seq[HirNode] = @[]
|
var args: seq[HirNode] = @[]
|
||||||
args.add(ctx.lowerExpr(expr.exprCallCallee.exprFieldObj))
|
args.add(ctx.lowerExpr(expr.exprCallCallee.exprFieldObj))
|
||||||
for arg in expr.exprCallArgs:
|
for arg in expr.exprCallArgs:
|
||||||
args.add(ctx.lowerExpr(arg))
|
args.add(ctx.lowerExpr(arg))
|
||||||
return hirCall(mangledName, args, typ, loc)
|
return hirCall(mangledName, args, typ, loc)
|
||||||
|
|
||||||
|
# Not a method call - treat as field access + call (function pointer)
|
||||||
|
let callee = ctx.lowerExpr(expr.exprCallCallee)
|
||||||
|
var args: seq[HirNode] = @[]
|
||||||
|
for arg in expr.exprCallArgs:
|
||||||
|
args.add(ctx.lowerExpr(arg))
|
||||||
|
return HirNode(kind: hCallIndirect, callIndirectCallee: callee,
|
||||||
|
callIndirectArgs: args, typ: typ, loc: loc)
|
||||||
|
|
||||||
# Regular function call
|
# Regular function call
|
||||||
var calleeName = ""
|
var calleeName = ""
|
||||||
|
|||||||
@@ -573,3 +573,11 @@ proc analyze*(modu: Module): SemaResult =
|
|||||||
sema.collectGlobals()
|
sema.collectGlobals()
|
||||||
sema.checkBodies()
|
sema.checkBodies()
|
||||||
result = SemaResult(diagnostics: sema.diagnostics)
|
result = SemaResult(diagnostics: sema.diagnostics)
|
||||||
|
|
||||||
|
proc analyzeFull*(modu: Module): tuple[result: SemaResult, sema: Sema] =
|
||||||
|
## Analyze module and return both result and full Sema context
|
||||||
|
## Use this when you need the Sema for lowering (method table, etc.)
|
||||||
|
var sema = Sema(module: modu, globalScope: newScope())
|
||||||
|
sema.collectGlobals()
|
||||||
|
sema.checkBodies()
|
||||||
|
result = (SemaResult(diagnostics: sema.diagnostics), sema)
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user