diff options
author | Himbeer <himbeer@disroot.org> | 2024-09-04 16:03:20 +0200 |
---|---|---|
committer | Himbeer <himbeer@disroot.org> | 2024-09-04 16:03:20 +0200 |
commit | 413e267d0ed01c426002ec6488f05a5d7a619e5a (patch) | |
tree | be54b983ff508f2c81837e2baa6734ae8d37c24b | |
parent | f27272532c25180a7f2d4b0f5f1d50c0a1a04564 (diff) |
Require extern functions to be declared
-rw-r--r-- | expression.go | 1 | ||||
-rw-r--r-- | generate.go | 14 | ||||
-rw-r--r-- | generate_error.go | 12 | ||||
-rw-r--r-- | lex.go | 2 | ||||
-rw-r--r-- | parse.go | 27 | ||||
-rw-r--r-- | 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 { @@ -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": @@ -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, @@ -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 |