aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-09-04 16:03:20 +0200
committerHimbeer <himbeer@disroot.org>2024-09-04 16:03:20 +0200
commit413e267d0ed01c426002ec6488f05a5d7a619e5a (patch)
treebe54b983ff508f2c81837e2baa6734ae8d37c24b
parentf27272532c25180a7f2d4b0f5f1d50c0a1a04564 (diff)
Require extern functions to be declared
-rw-r--r--expression.go1
-rw-r--r--generate.go14
-rw-r--r--generate_error.go12
-rw-r--r--lex.go2
-rw-r--r--parse.go27
-rw-r--r--token.go3
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