From 7ac90260af2fed72e0f5b8f4cc18deecf2bb2ecb Mon Sep 17 00:00:00 2001 From: Mattias Hansson Date: Wed, 5 Nov 2025 18:08:25 +0100 Subject: [PATCH] Added function handling using FuncHandler --- internal/commands/call.go | 77 +++++++++++++++++++++++++++++++++++++++ internal/commands/fend.go | 43 ++++++++++++++++++++++ internal/commands/func.go | 44 ++++++++++++++++++++++ main.go | 3 ++ 4 files changed, 167 insertions(+) create mode 100644 internal/commands/call.go create mode 100644 internal/commands/fend.go create mode 100644 internal/commands/func.go diff --git a/internal/commands/call.go b/internal/commands/call.go new file mode 100644 index 0000000..d3fb175 --- /dev/null +++ b/internal/commands/call.go @@ -0,0 +1,77 @@ +package commands + +import ( + "strings" + + "c65gm/internal/compiler" + "c65gm/internal/preproc" + "c65gm/internal/utils" +) + +// CallCommand handles function calls +// Syntax: +// +// CALL funcname # void call +// CALL funcname ( arg1 arg2 ) # call with arguments +// funcname # implicit call syntax +// funcname ( arg1 arg2 ) # implicit call with args +// +// Arguments can be: +// - Variables: varname +// - Constants: 123, $FF +// - Labels: @labelname +// - Strings: "text" +type CallCommand struct { + funcHandler *compiler.FunctionHandler + asmOutput []string +} + +// NewCallCommand creates a CallCommand with access to function registry +func NewCallCommand(funcHandler *compiler.FunctionHandler) *CallCommand { + return &CallCommand{ + funcHandler: funcHandler, + } +} + +func (c *CallCommand) WillHandle(line preproc.Line) bool { + params, err := utils.ParseParams(line.Text) + if err != nil || len(params) == 0 { + return false + } + + // Check if starts with CALL keyword + if strings.ToUpper(params[0]) == "CALL" { + return true + } + + // Check if first token is a declared function + if c.funcHandler.FuncExists(params[0]) { + return true + } + + // For intuitive syntax like "funcname(args)", extract function name + // by looking for '(' and taking everything before it + firstToken := params[0] + if idx := strings.IndexByte(firstToken, '('); idx > 0 { + funcName := firstToken[:idx] + return c.funcHandler.FuncExists(funcName) + } + + return false +} + +func (c *CallCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext) error { + c.asmOutput = nil + + asm, err := ctx.FunctionHandler.HandleFuncCall(line) + if err != nil { + return err + } + + c.asmOutput = asm + return nil +} + +func (c *CallCommand) Generate(_ *compiler.CompilerContext) ([]string, error) { + return c.asmOutput, nil +} diff --git a/internal/commands/fend.go b/internal/commands/fend.go new file mode 100644 index 0000000..f8ee2f5 --- /dev/null +++ b/internal/commands/fend.go @@ -0,0 +1,43 @@ +package commands + +import ( + "fmt" + "strings" + + "c65gm/internal/compiler" + "c65gm/internal/preproc" + "c65gm/internal/utils" +) + +// FendCommand handles FEND (function end) +// Syntax: +// +// FEND +type FendCommand struct { +} + +func (c *FendCommand) WillHandle(line preproc.Line) bool { + params, err := utils.ParseParams(line.Text) + if err != nil || len(params) == 0 { + return false + } + return strings.ToUpper(params[0]) == "FEND" +} + +func (c *FendCommand) Interpret(line preproc.Line, _ *compiler.CompilerContext) error { + params, err := utils.ParseParams(line.Text) + if err != nil { + return err + } + + if len(params) != 1 { + return fmt.Errorf("FEND: no parameters expected, got %d", len(params)-1) + } + + return nil +} + +func (c *FendCommand) Generate(ctx *compiler.CompilerContext) ([]string, error) { + ctx.FunctionHandler.EndFunction() + return []string{"\trts"}, nil +} diff --git a/internal/commands/func.go b/internal/commands/func.go new file mode 100644 index 0000000..77fe4d7 --- /dev/null +++ b/internal/commands/func.go @@ -0,0 +1,44 @@ +package commands + +import ( + "strings" + + "c65gm/internal/compiler" + "c65gm/internal/preproc" + "c65gm/internal/utils" +) + +// FuncCommand handles FUNC declarations +// Syntax: +// +// FUNC name # void function +// FUNC name ( param1 param2 ) # function with parameters +// FUNC name ( in:x out:y io:z ) # with direction modifiers +// FUNC name ( {BYTE temp} out:result ) # with implicit declarations +type FuncCommand struct { + asmOutput []string +} + +func (c *FuncCommand) WillHandle(line preproc.Line) bool { + params, err := utils.ParseParams(line.Text) + if err != nil || len(params) == 0 { + return false + } + return strings.ToUpper(params[0]) == "FUNC" +} + +func (c *FuncCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext) error { + c.asmOutput = nil + + asm, err := ctx.FunctionHandler.HandleFuncDecl(line) + if err != nil { + return err + } + + c.asmOutput = asm + return nil +} + +func (c *FuncCommand) Generate(_ *compiler.CompilerContext) ([]string, error) { + return c.asmOutput, nil +} diff --git a/main.go b/main.go index 7e3d9a9..dda09bb 100644 --- a/main.go +++ b/main.go @@ -90,6 +90,9 @@ func registerCommands(comp *compiler.Compiler) { comp.Registry().Register(&commands.WhileCommand{}) comp.Registry().Register(&commands.BreakCommand{}) comp.Registry().Register(&commands.WendCommand{}) + comp.Registry().Register(&commands.FuncCommand{}) + comp.Registry().Register(commands.NewCallCommand(comp.Context().FunctionHandler)) + comp.Registry().Register(&commands.FendCommand{}) }