diff options
| author | Marc Vertes <mvertes@free.fr> | 2023-09-06 08:49:19 +0200 |
|---|---|---|
| committer | Marc Vertes <mvertes@free.fr> | 2023-09-06 08:49:19 +0200 |
| commit | 6dd78f44adf6fb032d0ecd9db813651b9524fcac (patch) | |
| tree | d1d4b3305db708614f147b2294b4b0e28336a55d /parser | |
| parent | 4241593b42bffac2f8fcb63f1e88621fe025e360 (diff) | |
chore: refactor some APIs
The scanner returns a slice of pointers to tokens instead of a
slice of tokens. The parser now pass the initial node context.
Diffstat (limited to 'parser')
| -rw-r--r-- | parser/dot.go | 5 | ||||
| -rw-r--r-- | parser/node.go | 15 | ||||
| -rw-r--r-- | parser/parse.go | 51 | ||||
| -rw-r--r-- | parser/parse_test.go | 74 |
4 files changed, 94 insertions, 51 deletions
diff --git a/parser/dot.go b/parser/dot.go index f486cd5..11d5014 100644 --- a/parser/dot.go +++ b/parser/dot.go @@ -50,7 +50,10 @@ func (n *Node) astDot(out io.Writer, label string) { for _, c := range nod.Child { anc[c] = nod } - name := strings.ReplaceAll(nod.Name(), `"`, `\"`) + name := "" + if nod.Token != nil { + name = strings.ReplaceAll(nod.Name(), `"`, `\"`) + } fmt.Fprintf(out, "%d [label=\"%s\"]; ", index[nod], name) if anc[nod] != nil { fmt.Fprintf(out, "%d -> %d; ", index[anc[nod]], index[nod]) diff --git a/parser/node.go b/parser/node.go index d2f13ef..b6e34cd 100644 --- a/parser/node.go +++ b/parser/node.go @@ -3,9 +3,9 @@ package parser import "github.com/gnolang/parscan/scanner" type Node struct { - Child []*Node // sub-tree nodes - scanner.Token // token at origin of the node - Kind // Node kind, depends on the language spec + Child []*Node // sub-tree nodes + *scanner.Token // token at origin of the node + Kind // Node kind, depends on the language spec } // TODO: remove it in favor of Walk2 @@ -39,3 +39,12 @@ func (n *Node) Walk2(a *Node, i int, in, out func(*Node, *Node, int) bool) (stop } return } + +func (n *Node) RemoveChild(i int) { + n.Child = append(n.Child[:i], n.Child[i+1:]...) +} + +func (n *Node) InsertChild(node *Node, i int) { + n.Child = append(n.Child[:i+1], n.Child[i:]...) + n.Child[i] = node +} diff --git a/parser/parse.go b/parser/parse.go index 08fbdbd..ca89467 100644 --- a/parser/parse.go +++ b/parser/parse.go @@ -10,6 +10,7 @@ const ( Call Index Decl + MultiOp ) type NodeSpec struct { @@ -23,21 +24,22 @@ type Parser struct { Spec map[string]NodeSpec } -func (p *Parser) Parse(src string) (n []*Node, err error) { +func (p *Parser) Parse(src string, ctx *Node) (nodes []*Node, err error) { tokens, err := p.Scan(src) if err != nil { return } - return p.ParseTokens(tokens) + return p.ParseTokens(tokens, ctx) } -func (p *Parser) ParseTokens(tokens []scanner.Token) (roots []*Node, err error) { +func (p *Parser) ParseTokens(tokens []*scanner.Token, ctx *Node) (nodes []*Node, err error) { // TODO: error handling. var root *Node // current root node var expr *Node // current expression root node var prev, c *Node // previous and current nodes var lce *Node // last complete expression node unaryOp := map[*Node]bool{} // unaryOp indicates if a node is an unary operator. + prevToken := map[*Node]*scanner.Token{} for i, t := range tokens { prev = c @@ -45,6 +47,9 @@ func (p *Parser) ParseTokens(tokens []scanner.Token) (roots []*Node, err error) Token: t, Kind: p.Spec[t.Name()].Kind, } + if i > 0 { + prevToken[c] = tokens[i-1] + } if c.Kind == Comment { continue } @@ -90,7 +95,7 @@ func (p *Parser) ParseTokens(tokens []scanner.Token) (roots []*Node, err error) } tcont := t.Content() s := tcont[t.Start() : len(tcont)-t.End()] - n2, err := p.Parse(s) + n2, err := p.Parse(s, c) if err != nil { return nil, err } @@ -99,10 +104,12 @@ func (p *Parser) ParseTokens(tokens []scanner.Token) (roots []*Node, err error) // Process the end of an expression or a statement. if t.IsSeparator() { - if expr != nil && p.hasProp(root, Stmt) { + if t.Content() == "," && ctx.Kind != BlockParen { + // ignore comma separator in field lists + } else if expr != nil && p.hasProp(root, Stmt) { root.Child = append(root.Child, expr) if p.hasProp(expr, ExprSep) { - roots = append(roots, root) + nodes = append(nodes, root) root = nil } expr = nil @@ -110,7 +117,7 @@ func (p *Parser) ParseTokens(tokens []scanner.Token) (roots []*Node, err error) if expr != nil { root = expr } - roots = append(roots, root) + nodes = append(nodes, root) expr = nil root = nil } @@ -190,9 +197,31 @@ func (p *Parser) ParseTokens(tokens []scanner.Token) (roots []*Node, err error) root = expr } if root != nil { - roots = append(roots, root) + // /* + if p.hasProp(root, MultiOp) { + for { + if !p.fixMultiOp(root, prevToken) { + break + } + } + } + // */ + nodes = append(nodes, root) + } + return nodes, err +} + +func (p *Parser) fixMultiOp(root *Node, prevToken map[*Node]*scanner.Token) bool { + for i, c := range root.Child { + for j, cc := range c.Child { + if pt := prevToken[cc]; pt != nil && pt.Content() == "," { + c.RemoveChild(j) + root.InsertChild(cc, i) + return true + } + } } - return roots, err + return false } func (p *Parser) hasProp(n *Node, prop uint) bool { return p.Spec[n.Name()].Flags&prop != 0 } @@ -202,7 +231,7 @@ func (p *Parser) isExpr(n *Node) bool { return !p.isStatement(n) && func (p *Parser) isSep(n *Node) bool { return n.Token.Kind() == scanner.Separator } func (p *Parser) IsBlock(n *Node) bool { return n.Token.Kind() == scanner.Block } -func (p *Parser) precedenceToken(t scanner.Token) int { +func (p *Parser) precedenceToken(t *scanner.Token) int { s := t.Content() if l := t.Start(); l > 0 { s = s[:l] @@ -210,6 +239,6 @@ func (p *Parser) precedenceToken(t scanner.Token) int { return p.Spec[s].Order } -func (p *Parser) canCallToken(t scanner.Token) bool { +func (p *Parser) canCallToken(t *scanner.Token) bool { return p.precedenceToken(t) == 0 || p.Spec[t.Name()].Flags&Call != 0 } diff --git a/parser/parse_test.go b/parser/parse_test.go index 0a41d09..ffc0f53 100644 --- a/parser/parse_test.go +++ b/parser/parse_test.go @@ -66,8 +66,8 @@ var GoParser = &Parser{ "+": {Kind: OpAdd, Order: 5}, "-": {Kind: OpSubtract, Order: 5}, "<": {Kind: OpInferior, Order: 6}, - ":=": {Kind: OpDefine, Order: 7}, - "=": {Kind: OpAssign, Order: 7}, + ":=": {Kind: OpDefine, Flags: MultiOp, Order: 7}, + "=": {Kind: OpAssign, Flags: MultiOp, Order: 7}, "if": {Kind: StmtIf, Flags: Stmt | ExprSep}, "func": {Kind: DeclFunc, Flags: Decl | Call}, "return": {Kind: StmtReturn, Flags: Stmt}, @@ -90,7 +90,7 @@ func TestParse(t *testing.T) { var err error errStr := "" n := &Node{} - if n.Child, err = GoParser.Parse(test.src); err != nil { + if n.Child, err = GoParser.Parse(test.src, n); err != nil { errStr = err.Error() } if errStr != test.err { @@ -192,39 +192,41 @@ var goTests = []struct { }, { // #26 src: "a := 1 // This is a comment", dot: `digraph ast { 0 [label=""]; 1 [label=":="]; 0 -> 1; 2 [label="a"]; 1 -> 2; 3 [label="1"]; 1 -> 3; }`, - //src: "f(i) + f(j)(4)", // not ok /* - }, { // #26 - src: "if i < 2 {return i}; return f(i-2) + f(i-1)", - }, { // #27 - src: "for i < 2 { println(i) }", - }, { // #28 - src: "func f(i int) (int) { if i < 2 { return i}; return f(i-2) + f(i-1) }", - }, { // #29 - src: "a := []int{3, 4}", - }, { // #30 - //src: "a := struct{int}", - src: "a, b = c, d", - }, { // #31 - //src: "a := [2]int{3, 4}", - src: `fmt.Println("Hello")`, - //src: "(1 + 2) * (3 - 4)", - //src: "1 + (1 + 2)", - }, { // #32 - //src: `a(3)(4)`, - //src: `3 + 2 * a(3) + 5`, - //src: `3 + 2 * a(3)(4) + (5)`, - //src: `(a(3))(4)`, - src: `a(3)(4)`, - dot: `digraph ast { 0 [label=""]; 1 [label="Call"]; 0 -> 1; 2 [label="Call"]; 1 -> 2; 3 [label="a"]; 2 -> 3; 4 [label="(..)"]; 2 -> 4; 5 [label="3"]; 4 -> 5; 6 [label="(..)"]; 1 -> 6; 7 [label="4"]; 6 -> 7; }`, - //src: `println("Hello")`, - //src: `a.b.c + 3`, - }, { // #33 - src: `func f(a int, b int) {return a + b}; f(1+2)`, - }, { // #34 - src: `if a == 1 { - println(2) - } - println("bye")`, + }, { // #27 + src: "a, b, c = 1, f(2), 3", + //src: "f(i) + f(j)(4)", // not ok + }, { // #26 + src: "if i < 2 {return i}; return f(i-2) + f(i-1)", + }, { // #27 + src: "for i < 2 { println(i) }", + }, { // #28 + src: "func f(i int) (int) { if i < 2 { return i}; return f(i-2) + f(i-1) }", + }, { // #29 + src: "a := []int{3, 4}", + }, { // #30 + //src: "a := struct{int}", + src: "a, b = c, d", + }, { // #31 + //src: "a := [2]int{3, 4}", + src: `fmt.Println("Hello")`, + //src: "(1 + 2) * (3 - 4)", + //src: "1 + (1 + 2)", + }, { // #32 + //src: `a(3)(4)`, + //src: `3 + 2 * a(3) + 5`, + //src: `3 + 2 * a(3)(4) + (5)`, + //src: `(a(3))(4)`, + src: `a(3)(4)`, + dot: `digraph ast { 0 [label=""]; 1 [label="Call"]; 0 -> 1; 2 [label="Call"]; 1 -> 2; 3 [label="a"]; 2 -> 3; 4 [label="(..)"]; 2 -> 4; 5 [label="3"]; 4 -> 5; 6 [label="(..)"]; 1 -> 6; 7 [label="4"]; 6 -> 7; }`, + //src: `println("Hello")`, + //src: `a.b.c + 3`, + }, { // #33 + src: `func f(a int, b int) {return a + b}; f(1+2)`, + }, { // #34 + src: `if a == 1 { + println(2) + } + println("bye")`, */ }} |
