From 6e2349e875e77d8af8b7d6f00f718db6813b40c1 Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Fri, 3 Nov 2023 19:05:14 +0100 Subject: feat: add support for control flow operators in expressions Logical operators `&&` (and), `||` (or) are now parsed in expressions. The control flow tokens (labels, conditional jumps) are added accordingly. --- parser/parse.go | 110 -------------------------------------------------------- 1 file changed, 110 deletions(-) (limited to 'parser/parse.go') diff --git a/parser/parse.go b/parser/parse.go index 757468c..fb8ae2c 100644 --- a/parser/parse.go +++ b/parser/parse.go @@ -441,116 +441,6 @@ func (p *Parser) ParseReturn(in Tokens) (out Tokens, err error) { return out, err } -func (p *Parser) ParseExpr(in Tokens) (out Tokens, err error) { - log.Println("ParseExpr in:", in) - var ops Tokens - var vl int - // - // Process tokens from last to first, the goal is to reorder the tokens in - // a stack machine processing order, so it can be directly interpreted. - // - for i := len(in) - 1; i >= 0; i-- { - t := in[i] - // temporary assumptions: binary operators, returning 1 value - switch t.Id { - case lang.Ident: - // resolve symbol if not a selector rhs. - // TODO: test for selector expr. - _, sc, ok := p.getSym(t.Str, p.scope) - if ok && sc != "" { - t.Str = sc + "/" + t.Str - } - out = append(out, t) - vl++ - case lang.Int, lang.String: - out = append(out, t) - vl++ - case lang.Define, lang.Add, lang.Sub, lang.Assign, lang.Equal, lang.Greater, lang.Less, lang.Mul: - // TODO: handle operator precedence to swap operators / operands if necessary - if vl < 2 { - ops = append(ops, t) - break - } - case lang.ParenBlock: - // If the previous token is an arithmetic, logic or assign operator then - // this parenthesis block is an enclosed expr, otherwise a call expr. - if i == 0 || in[i-1].Id.IsOperator() { - out = append(out, t) - vl++ - break - } - // The call expression can be a function call, a conversion, - // a type assersion (including for type switch) - // func call: push args and func address then call - out = append(out, t) - vl++ - if t2 := in[i-1]; t2.Id == lang.Ident { - if s, sc, ok := p.getSym(t2.Str, p.scope); ok { - log.Println("callExpr:", t2.Str, p.scope, s, ok, sc) - if s.kind == symValue { - // Store the number of input parameters in the token Beg field. - ops = append(ops, scanner.Token{Str: "callX", Id: lang.CallX, Pos: t.Pos, Beg: p.numItems(t.Block(), lang.Comma)}) - break - } - } - } - ops = append(ops, scanner.Token{Str: "call", Id: lang.Call, Pos: t.Pos}) - } - if lops, lout := len(ops), len(out); lops > 0 && vl > lops { - op := ops[lops-1] - ops = ops[:lops-1] - // Reorder tokens according to operator precedence rules. - if p.precedence(out[lout-2]) > p.precedence(op) { - op, out[lout-1], out[lout-2] = out[lout-2], op, out[lout-1] - if p.precedence(out[lout-3]) > p.precedence(out[lout-1]) { - out[lout-1], out[lout-2], out[lout-3] = out[lout-3], out[lout-1], out[lout-2] - } - } - out = append(out, op) - vl-- - } - } - out = append(out, ops...) // TODO: verify that ops should be added in this order. - - log.Println("ParseExpr out:", out, "vl:", vl, "ops:", ops) - // The tokens are now properly ordered, process nested blocks. - for i := len(out) - 1; i >= 0; i-- { - t := out[i] - var toks Tokens - switch t.Id { - case lang.ParenBlock, lang.BracketBlock: - if toks, err = p.ParseExprStr(t.Block()); err != nil { - return out, err - } - default: - continue - } - - // replace block token by its parsed result. - log.Println("toks:", toks) - out2 := append(Tokens{}, out[:i]...) - out2 = append(out2, toks...) - out = append(out2, out[i+1:]...) - } - log.Println("Final out:", out) - return out, err -} - -func (p *Parser) ParseExprStr(s string) (tokens Tokens, err error) { - if tokens, err = p.Scan(s, false); err != nil { - return - } - var result Tokens - for _, sub := range tokens.Split(lang.Comma) { - toks, err := p.ParseExpr(sub) - if err != nil { - return result, err - } - result = append(toks, result...) - } - return result, err -} - func (p *Parser) numItems(s string, sep lang.TokenId) int { tokens, err := p.Scan(s, false) if err != nil { -- cgit v1.2.3