diff options
author | Himbeer <himbeer@disroot.org> | 2024-08-30 11:45:11 +0200 |
---|---|---|
committer | Himbeer <himbeer@disroot.org> | 2024-08-30 11:45:11 +0200 |
commit | 4bfdd92015153c79c7a069c085b5fb0e4cc6bfaf (patch) | |
tree | 3d29f9adb1959a684c96952476f6540d271ed0b8 | |
parent | 479ae18be6a21f71090e2f25435f585846de152c (diff) |
Implement function calls
-rw-r--r-- | GRAMMAR.txt | 4 | ||||
-rw-r--r-- | expression.go | 19 | ||||
-rw-r--r-- | generate.go | 21 | ||||
-rw-r--r-- | parse.go | 67 |
4 files changed, 110 insertions, 1 deletions
diff --git a/GRAMMAR.txt b/GRAMMAR.txt index c687722..9e30c24 100644 --- a/GRAMMAR.txt +++ b/GRAMMAR.txt @@ -20,8 +20,10 @@ term -> numeral ( ( "<<" | ">>" ) numeral )* numeral -> factor ( ( "+" | "-" ) factor )* factor -> unary ( ( "*" | "/" ) unary )* unary -> ( "-" | "!" | "~" )? primary -primary -> grouping | literal +primary -> grouping | literal | call grouping -> "(" expression ")" literal -> string | number string -> STRING* number -> NUMBER IDENTIFIER +call -> IDENTIFIER "(" arg? ")" +arg -> expression ( "," arg )? diff --git a/expression.go b/expression.go index 6cc6539..c62918c 100644 --- a/expression.go +++ b/expression.go @@ -257,3 +257,22 @@ func (g *groupingExpr) markExprExpr() {} func (g *groupingExpr) markPrimaryExpr() {} func (g *groupingExpr) line() int { return g.ln } + +type callExpr struct { + funcName string + args *argument + ln int +} + +func (c *callExpr) markExpr() {} + +func (c *callExpr) markExprExpr() {} + +func (c *callExpr) markPrimaryExpr() {} + +func (c *callExpr) line() int { return c.ln } + +type argument struct { + value exprExpr + next *argument +} diff --git a/generate.go b/generate.go index 317e11c..3e21a0c 100644 --- a/generate.go +++ b/generate.go @@ -378,3 +378,24 @@ func (n *numberExpr) generate(w io.Writer) (string, error) { return fmt.Sprintf("%d", num), nil } + +func (c *callExpr) generate(w io.Writer) (string, error) { + ret := allocReg() + + fmt.Fprintf(w, "%s =w call $%s(", ret, c.funcName) + + delim := "" + for arg := c.args; arg != nil; arg = arg.next { + reg, err := arg.value.generate(w) + if err != nil { + return "", err + } + + fmt.Fprintf(w, "w %s%s", reg, delim) + delim = "," + } + + fmt.Fprintf(w, ")\n") + + return ret, nil +} @@ -651,6 +651,14 @@ func parsePrimary(toks *tokens) (primaryExpr, error) { return lit, nil } + call, err := parseCall(toks) + if err != nil { + return nil, err + } + if call != nil { + return call, nil + } + return nil, expectedPrimary{got: toks.current()} } @@ -761,3 +769,62 @@ func parseNumber(toks *tokens) (*numberExpr, error) { return &numberExpr{typ: typeTok.value, s: numTok.value, ln: numTok.line}, nil } + +func parseCall(toks *tokens) (*callExpr, error) { + nameTok, ok := toks.consumeToken() + if !ok { + return nil, unexpectedEOF + } + + if nameTok.kind != identifier { + toks.unreadToken() + return nil, nil + } + + if err := toks.mustMatch(lparen); err != nil { + return nil, err + } + + args, err := parseArg(toks) + if err != nil { + return nil, err + } + + if err := toks.mustMatch(rparen); err != nil { + return nil, err + } + + return &callExpr{funcName: nameTok.value, args: args, ln: nameTok.line}, nil +} + +func parseArg(toks *tokens) (*argument, error) { + ok, err := toks.match(rparen) + if err != nil { + return nil, err + } + toks.unreadToken() + if ok { + return nil, nil + } + + arg, err := parseExpression(toks) + if err != nil { + return nil, err + } + + ok, err = toks.match(comma) + if err != nil { + return nil, err + } + if !ok { + toks.unreadToken() + return &argument{value: arg}, nil + } + + next, err := parseArg(toks) + if err != nil { + return nil, err + } + + return &argument{value: arg, next: next}, nil +} |