From 413e267d0ed01c426002ec6488f05a5d7a619e5a Mon Sep 17 00:00:00 2001 From: Himbeer Date: Wed, 4 Sep 2024 16:03:20 +0200 Subject: Require extern functions to be declared --- expression.go | 1 + generate.go | 14 ++++++++++++++ generate_error.go | 12 +++++++++--- lex.go | 2 ++ parse.go | 27 ++++++++++++++++++++------- token.go | 3 +++ 6 files changed, 49 insertions(+), 10 deletions(-) diff --git a/expression.go b/expression.go index 99bd4cb..6ab30c2 100644 --- a/expression.go +++ b/expression.go @@ -41,6 +41,7 @@ func (l linkage) String() string { type functionExpr struct { link linkage + external bool name string params *paramExpr returnType string diff --git a/generate.go b/generate.go index b8c6ba2..a5ddf7f 100644 --- a/generate.go +++ b/generate.go @@ -90,6 +90,11 @@ func generateFunction(function *functionExpr, w io.Writer) error { defer func() { currentFunc = "" }() funcs[currentFunc] = struct{}{} + + if function.external { + return nil + } + localConsts[currentFunc] = map[string]string{} localMuts[currentFunc] = map[string]struct{}{} @@ -579,6 +584,15 @@ func (n *numberExpr) generate(w io.Writer) (string, error) { } func (c *callExpr) generate(w io.Writer) (string, error) { + _, ok := funcs[c.funcName] + if !ok { + return "", errUndeclared{ + name: c.funcName, + isFunc: true, + line: c.line(), + } + } + ret := allocReg() fmt.Fprintf(w, "%s =w call $%s(", ret, c.funcName) diff --git a/generate_error.go b/generate_error.go index 8dfd964..e89add2 100644 --- a/generate_error.go +++ b/generate_error.go @@ -16,12 +16,18 @@ func (e errAlreadyDeclared) Error() string { } type errUndeclared struct { - name string - line int + name string + isFunc bool + line int } func (e errUndeclared) Error() string { - return fmt.Sprintf("%d: undeclared variable %q\n", e.line, e.name) + kind := "variable" + if e.isFunc { + kind = "function" + } + + return fmt.Sprintf("%d: undeclared %s %q\n", e.line, kind, e.name) } type errImmutable struct { diff --git a/lex.go b/lex.go index f0631da..621ed01 100644 --- a/lex.go +++ b/lex.go @@ -304,6 +304,8 @@ func addKeywordOrIdentifier(name string, line int) token { switch name { case "export": return token{kind: export, line: line} + case "extern": + return token{kind: extern, line: line} case "func": return token{kind: function, line: line} case "return": diff --git a/parse.go b/parse.go index a577f09..d2f9990 100644 --- a/parse.go +++ b/parse.go @@ -93,21 +93,33 @@ func parseToplevel(toks *tokens, errs chan<- error) expression { } func parseFunction(toks *tokens, errs chan<- error) *functionExpr { - var link linkage - - ok, err := toks.match(export) + exported, err := toks.match(export) if err != nil { errs <- err return nil } line := toks.current().line - if ok { - link = exportLinkage - } else { + var external bool + if !exported { toks.unreadToken() + + external, err = toks.match(extern) + if err != nil { + errs <- err + return nil + } + if !external { + toks.unreadToken() + } + } + + var link linkage + switch { + case exported: + link = exportLinkage } - ok, err = toks.match(function) + ok, err := toks.match(function) if err != nil { errs <- err return nil @@ -171,6 +183,7 @@ func parseFunction(toks *tokens, errs chan<- error) *functionExpr { return &functionExpr{ link: link, + external: external, name: nameTok.value, params: params, returnType: returnTypeTok.value, diff --git a/token.go b/token.go index 42c8041..b1e2dd8 100644 --- a/token.go +++ b/token.go @@ -100,6 +100,8 @@ func (k tokenKind) String() string { return "number" case export: return "export" + case extern: + return "extern" case function: return "func" case ret: @@ -161,6 +163,7 @@ const ( str number export + extern function ret constKeyword -- cgit v1.2.3