aboutsummaryrefslogtreecommitdiff
path: root/parse.go
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-09-05 13:26:48 +0200
committerHimbeer <himbeer@disroot.org>2024-09-05 13:35:38 +0200
commitfdfcd6d8d0fe79138a2e5bf66ae7c476c8db9c75 (patch)
treea8f252fdc893038eaef50e0771c8065ea16c0d51 /parse.go
parent413e267d0ed01c426002ec6488f05a5d7a619e5a (diff)
Switch to signature-based extern function declarations
Diffstat (limited to 'parse.go')
-rw-r--r--parse.go189
1 files changed, 140 insertions, 49 deletions
diff --git a/parse.go b/parse.go
index d2f9990..4983c65 100644
--- a/parse.go
+++ b/parse.go
@@ -72,7 +72,13 @@ func parse(toks *tokens, root chan<- *rootExpr, errs chan<- error) {
func parseRoot(toks *tokens, errs chan<- error) *rootExpr {
toplevels := make([]expression, 0)
for !toks.eof() {
- if toplevel := parseToplevel(toks, errs); toplevel != nil {
+ toplevel, err := parseToplevel(toks)
+ if err != nil {
+ errs <- err
+ continue
+ }
+
+ if toplevel != nil {
toplevels = append(toplevels, toplevel)
}
}
@@ -82,114 +88,103 @@ func parseRoot(toks *tokens, errs chan<- error) *rootExpr {
}
}
-func parseToplevel(toks *tokens, errs chan<- error) expression {
- function := parseFunction(toks, errs)
- if function == nil {
- errs <- expectedToplevel{got: toks.current()}
- return nil
+func parseToplevel(toks *tokens) (expression, error) {
+ function, err := parseFunction(toks)
+ if err != nil {
+ return nil, err
+ }
+ if function != nil {
+ return function, nil
+ }
+
+ externFunc, err := parseExternFunc(toks)
+ if err != nil {
+ return nil, err
+ }
+ if externFunc != nil {
+ return externFunc, nil
}
- return function
+ return nil, expectedToplevel{got: toks.current()}
}
-func parseFunction(toks *tokens, errs chan<- error) *functionExpr {
+func parseFunction(toks *tokens) (*functionExpr, error) {
+ link := exportLinkage
+
exported, err := toks.match(export)
if err != nil {
- errs <- err
- return nil
+ return nil, err
}
line := toks.current().line
- 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
+ link = defaultLinkage
}
ok, err := toks.match(function)
if err != nil {
- errs <- err
- return nil
+ return nil, err
}
if !ok {
- return nil
+ toks.unreadToken()
+ if exported {
+ toks.unreadToken()
+ }
+ return nil, nil
}
nameTok, ok := toks.consumeToken()
if !ok {
- errs <- unexpectedEOF
- return nil
+ return nil, unexpectedEOF
}
if nameTok.kind != identifier {
- errs <- expected{want: identifier, got: nameTok}
- return nil
+ return nil, expected{want: identifier, got: nameTok}
}
if err := toks.mustMatch(lparen); err != nil {
- errs <- err
- return nil
+ return nil, err
}
var params *paramExpr
ok, err = toks.match(rparen)
if err != nil {
- errs <- err
- return nil
+ return nil, err
}
if !ok {
toks.unreadToken()
params, err = parseParam(toks)
if err != nil {
- errs <- err
- return nil
+ return nil, err
}
if err := toks.mustMatch(rparen); err != nil {
- errs <- err
- return nil
+ return nil, err
}
}
returnTypeTok, ok := toks.consumeToken()
if !ok {
- errs <- unexpectedEOF
- return nil
+ return nil, unexpectedEOF
}
if returnTypeTok.kind != identifier {
- errs <- expected{want: identifier, got: returnTypeTok}
- return nil
+ return nil, expected{want: identifier, got: returnTypeTok}
}
blk, err := parseBlock(toks)
if err != nil {
- errs <- err
- return nil
+ return nil, err
}
return &functionExpr{
link: link,
- external: external,
name: nameTok.value,
params: params,
returnType: returnTypeTok.value,
blk: blk,
ln: line,
- }
+ }, nil
}
func parseParam(toks *tokens) (*paramExpr, error) {
@@ -231,6 +226,102 @@ func parseParam(toks *tokens) (*paramExpr, error) {
}, nil
}
+func parseExternFunc(toks *tokens) (*externFuncExpr, error) {
+ ok, err := toks.match(extern)
+ if err != nil {
+ return nil, err
+ }
+ if !ok {
+ toks.unreadToken()
+ return nil, nil
+ }
+ line := toks.current().line
+
+ if err := toks.mustMatch(function); err != nil {
+ return nil, err
+ }
+
+ nameTok, ok := toks.consumeToken()
+ if !ok {
+ return nil, unexpectedEOF
+ }
+ if nameTok.kind != identifier {
+ return nil, expected{want: identifier, got: nameTok}
+ }
+
+ if err := toks.mustMatch(lparen); err != nil {
+ return nil, err
+ }
+
+ var params *signatureExpr
+
+ ok, err = toks.match(rparen)
+ if err != nil {
+ return nil, err
+ }
+ if !ok {
+ toks.unreadToken()
+
+ params, err = parseSignature(toks)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := toks.mustMatch(rparen); err != nil {
+ return nil, err
+ }
+ }
+
+ returnTypeTok, ok := toks.consumeToken()
+ if !ok {
+ return nil, unexpectedEOF
+ }
+ if returnTypeTok.kind != identifier {
+ return nil, expected{want: identifier, got: returnTypeTok}
+ }
+
+ if err := toks.mustMatch(semicolon); err != nil {
+ return nil, err
+ }
+ return &externFuncExpr{
+ name: nameTok.value,
+ params: params,
+ returnType: returnTypeTok.value,
+ ln: line,
+ }, nil
+}
+
+func parseSignature(toks *tokens) (*signatureExpr, error) {
+ typeTok, ok := toks.consumeToken()
+ if !ok {
+ return nil, unexpectedEOF
+ }
+ if typeTok.kind != identifier {
+ return nil, expected{want: identifier, got: typeTok}
+ }
+
+ var next *signatureExpr
+
+ ok, err := toks.match(comma)
+ if err != nil {
+ return nil, err
+ }
+ if ok {
+ next, err = parseSignature(toks)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ toks.unreadToken()
+ }
+
+ return &signatureExpr{
+ typ: typeTok.value,
+ next: next,
+ ln: typeTok.line,
+ }, nil
+}
+
func parseBlock(toks *tokens) (*blockExpr, error) {
if err := toks.mustMatch(lbrace); err != nil {
return nil, err