summaryrefslogtreecommitdiff
path: root/parser
diff options
context:
space:
mode:
authorMarc Vertes <mvertes@free.fr>2023-09-06 08:49:19 +0200
committerMarc Vertes <mvertes@free.fr>2023-09-06 08:49:19 +0200
commit6dd78f44adf6fb032d0ecd9db813651b9524fcac (patch)
treed1d4b3305db708614f147b2294b4b0e28336a55d /parser
parent4241593b42bffac2f8fcb63f1e88621fe025e360 (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.go5
-rw-r--r--parser/node.go15
-rw-r--r--parser/parse.go51
-rw-r--r--parser/parse_test.go74
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")`,
*/
}}