diff options
Diffstat (limited to 'parse.go')
-rw-r--r-- | parse.go | 189 |
1 files changed, 140 insertions, 49 deletions
@@ -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 |