aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-08-30 11:45:11 +0200
committerHimbeer <himbeer@disroot.org>2024-08-30 11:45:11 +0200
commit4bfdd92015153c79c7a069c085b5fb0e4cc6bfaf (patch)
tree3d29f9adb1959a684c96952476f6540d271ed0b8
parent479ae18be6a21f71090e2f25435f585846de152c (diff)
Implement function calls
-rw-r--r--GRAMMAR.txt4
-rw-r--r--expression.go19
-rw-r--r--generate.go21
-rw-r--r--parse.go67
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
+}
diff --git a/parse.go b/parse.go
index 289c205..5261dfe 100644
--- a/parse.go
+++ b/parse.go
@@ -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
+}