Browse Source

feat: Adding composition access to ECAL

Matthias Ladkau 3 years ago
parent
commit
c355fc5cbc

+ 6 - 4
lang/ecal/parser/const.go

@@ -71,10 +71,11 @@ const (
 	// Constructed tokens which are generated by the parser not the lexer
 
 	TokenSTATEMENTS // A code block
-	TokenFUNCCALL
-	TokenLIST  // List value
-	TokenMAP   // MAP value
-	TokenGUARD // Guard expressions for conditional statements
+	TokenFUNCCALL   // A function call
+	TokenCOMPACCESS // Access to a composition structure
+	TokenLIST       // List value
+	TokenMAP        // MAP value
+	TokenGUARD      // Guard expressions for conditional statements
 
 	TOKENodeSYMBOLS // Used to separate symbols from other tokens in this list
 
@@ -194,6 +195,7 @@ const (
 
 	NodeSTATEMENTS = "statements" // List of statements
 	NodeFUNCCALL   = "funccall"
+	NodeCOMPACCESS = "compaccess"
 
 	// Condition operators
 

+ 2 - 2
lang/ecal/parser/lexer_test.go

@@ -69,14 +69,14 @@ func TestEquals(t *testing.T) {
 		return
 	}
 
-	if ok, msg := l[0].Equals(l[1], false); ok || msg != `ID is different 49 vs 7
+	if ok, msg := l[0].Equals(l[1], false); ok || msg != `ID is different 50 vs 7
 Pos is different 0 vs 5
 Val is different not vs test
 Identifier is different false vs true
 Lline is different 1 vs 2
 Lpos is different 1 vs 2
 {
-  "ID": 49,
+  "ID": 50,
   "Pos": 0,
   "Val": "not",
   "Identifier": false,

+ 26 - 1
lang/ecal/parser/parser.go

@@ -33,6 +33,7 @@ func init() {
 
 		TokenSTATEMENTS: {NodeSTATEMENTS, nil, nil, nil, nil, 0, nil, nil},
 		TokenFUNCCALL:   {NodeFUNCCALL, nil, nil, nil, nil, 0, nil, nil},
+		TokenCOMPACCESS: {NodeCOMPACCESS, nil, nil, nil, nil, 0, nil, nil},
 		/*
 			TokenLIST:       {NodeLIST, nil, nil, nil, 0, nil, nil},
 			TokenMAP:        {NodeMAP, nil, nil, nil, 0, nil, nil},
@@ -50,6 +51,8 @@ func init() {
 
 		// Grouping symbols
 
+		TokenLBRACK: {"", nil, nil, nil, nil, 150, ndInner, nil},
+		TokenRBRACK: {"", nil, nil, nil, nil, 0, nil, nil},
 		TokenLPAREN: {"", nil, nil, nil, nil, 150, ndInner, nil},
 		TokenRPAREN: {"", nil, nil, nil, nil, 0, nil, nil},
 
@@ -365,7 +368,7 @@ func ndImport(p *parser, self *ASTNode) (*ASTNode, error) {
 ndIdentifier is to parse identifiers and function calls.
 */
 func ndIdentifier(p *parser, self *ASTNode) (*ASTNode, error) {
-	var parseMore, parseSegment, parseFuncCall func(parent *ASTNode) error
+	var parseMore, parseSegment, parseFuncCall, parseCompositionAccess func(parent *ASTNode) error
 
 	parseMore = func(current *ASTNode) error {
 		var err error
@@ -374,6 +377,8 @@ func ndIdentifier(p *parser, self *ASTNode) (*ASTNode, error) {
 			err = parseSegment(current)
 		} else if p.node.Token.ID == TokenLPAREN {
 			err = parseFuncCall(current)
+		} else if p.node.Token.ID == TokenLBRACK {
+			err = parseCompositionAccess(current)
 		}
 
 		return err
@@ -425,6 +430,26 @@ func ndIdentifier(p *parser, self *ASTNode) (*ASTNode, error) {
 		return err
 	}
 
+	parseCompositionAccess = func(current *ASTNode) error {
+		err := skipToken(p, TokenLBRACK)
+
+		ca := astNodeMap[TokenCOMPACCESS].instance(p, nil)
+		current.Children = append(current.Children, ca)
+
+		// Parse all the expressions inside the directives
+
+		exp, err := p.run(0)
+		if err == nil {
+			ca.Children = append(ca.Children, exp)
+
+			if err = skipToken(p, TokenRBRACK); err == nil {
+				err = parseMore(current)
+			}
+		}
+
+		return err
+	}
+
 	return self, parseMore(self)
 }
 

+ 74 - 6
lang/ecal/parser/parser_func_test.go

@@ -34,9 +34,6 @@ statements
 	}
 }
 
-/*
-TODO:
-
 func TestFunctionCalling(t *testing.T) {
 
 	input := `import "foo/bar.ecal" as foobar
@@ -46,14 +43,85 @@ statements
   import
     string: 'foo/bar.ecal'
     identifier: foobar
+  identifier: foobar
+    identifier: test
+      funccall
+`[1:]
+
+	if res, err := UnitTestParse("mytest", input); err != nil || fmt.Sprint(res) != expectedOutput {
+		t.Error("Unexpected parser output:\n", res, "expected was:\n", expectedOutput, "Error:", err)
+		return
+	}
+
+	input = `a := 1
+a().foo := x2.foo()
+a.b.c().foo := a()
+	`
+	expectedOutput = `
+statements
   :=
-    identifier: i
-    identifier: foobar
+    identifier: a
+    number: 1
+  :=
+    identifier: a
+      funccall
+      identifier: foo
+    identifier: x2
+      identifier: foo
+        funccall
+  :=
+    identifier: a
+      identifier: b
+        identifier: c
+          funccall
+          identifier: foo
+    identifier: a
+      funccall
 `[1:]
 
 	if res, err := UnitTestParse("mytest", input); err != nil || fmt.Sprint(res) != expectedOutput {
 		t.Error("Unexpected parser output:\n", res, "expected was:\n", expectedOutput, "Error:", err)
 		return
 	}
+
+	input = `a(1+2).foo := x2.foo(foo)
+a.b.c(x()).foo := a(1,a(),3, x, y) + 1
+	`
+	expectedOutput = `
+statements
+  :=
+    identifier: a
+      funccall
+        plus
+          number: 1
+          number: 2
+      identifier: foo
+    identifier: x2
+      identifier: foo
+        funccall
+          identifier: foo
+  :=
+    identifier: a
+      identifier: b
+        identifier: c
+          funccall
+            identifier: x
+              funccall
+          identifier: foo
+    plus
+      identifier: a
+        funccall
+          number: 1
+          identifier: a
+            funccall
+          number: 3
+          identifier: x
+          identifier: y
+      number: 1
+`[1:]
+
+	if res, err := UnitTestParseWithPPResult("mytest", input, ""); err != nil || fmt.Sprint(res) != expectedOutput {
+		t.Error("Unexpected parser output:\n", res, "expected was:\n", expectedOutput, "Error:", err)
+		return
+	}
 }
-*/

+ 14 - 58
lang/ecal/parser/parser_main_test.go

@@ -68,74 +68,30 @@ statements
 		return
 	}
 
-	input = `a := 1
-a().foo := x2.foo()
-a.b.c().foo := a()
+	input = `a := b[1 + 1]
+	a[4].foo["aaa"] := c[i]
 	`
 	expectedOutput = `
 statements
   :=
     identifier: a
-    number: 1
-  :=
-    identifier: a
-      funccall
-      identifier: foo
-    identifier: x2
-      identifier: foo
-        funccall
-  :=
-    identifier: a
-      identifier: b
-        identifier: c
-          funccall
-          identifier: foo
-    identifier: a
-      funccall
-`[1:]
-
-	if res, err := UnitTestParse("mytest", input); err != nil || fmt.Sprint(res) != expectedOutput {
-		t.Error("Unexpected parser output:\n", res, "expected was:\n", expectedOutput, "Error:", err)
-		return
-	}
-
-	input = `a(1+2).foo := x2.foo(foo)
-a.b.c(x()).foo := a(1,a(),3, x, y) + 1
-	`
-	expectedOutput = `
-statements
-  :=
-    identifier: a
-      funccall
+    identifier: b
+      compaccess
         plus
           number: 1
-          number: 2
-      identifier: foo
-    identifier: x2
-      identifier: foo
-        funccall
-          identifier: foo
+          number: 1
   :=
     identifier: a
-      identifier: b
-        identifier: c
-          funccall
-            identifier: x
-              funccall
-          identifier: foo
-    plus
-      identifier: a
-        funccall
-          number: 1
-          identifier: a
-            funccall
-          number: 3
-          identifier: x
-          identifier: y
-      number: 1
+      compaccess
+        number: 4
+      identifier: foo
+        compaccess
+          string: 'aaa'
+    identifier: c
+      compaccess
+        identifier: i
 `[1:]
-
-	if res, err := UnitTestParseWithPPResult("mytest", input, ""); err != nil || fmt.Sprint(res) != expectedOutput {
+	if res, err := UnitTestParse("mytest", input); err != nil || fmt.Sprint(res) != expectedOutput {
 		t.Error("Unexpected parser output:\n", res, "expected was:\n", expectedOutput, "Error:", err)
 		return
 	}

+ 7 - 5
lang/ecal/parser/prettyprinter.go

@@ -32,14 +32,15 @@ var bracketPrecedenceMap map[string]bool
 func init() {
 	prettyPrinterMap = map[string]*template.Template{
 
-		NodeSTRING: template.Must(template.New(NodeTRUE).Parse("{{.qval}}")),
-		NodeNUMBER: template.Must(template.New(NodeTRUE).Parse("{{.val}}")),
+		NodeSTRING: template.Must(template.New(NodeSTRING).Parse("{{.qval}}")),
+		NodeNUMBER: template.Must(template.New(NodeNUMBER).Parse("{{.val}}")),
 		// NodeIDENTIFIER - Special case (handled in code)
 
 		// Constructed tokens
 
 		// NodeSTATEMENTS - Special case (handled in code)
 		// NodeFUNCCALL - Special case (handled in code)
+		NodeCOMPACCESS + "_1": template.Must(template.New(NodeCOMPACCESS).Parse("[{{.c1}}]")),
 
 		/*
 
@@ -61,7 +62,7 @@ func init() {
 
 		// Arithmetic operators
 
-		NodePLUS + "_1":   template.Must(template.New(NodeMINUS).Parse("+{{.c1}}")),
+		NodePLUS + "_1":   template.Must(template.New(NodePLUS).Parse("+{{.c1}}")),
 		NodePLUS + "_2":   template.Must(template.New(NodePLUS).Parse("{{.c1}} + {{.c2}}")),
 		NodeMINUS + "_1":  template.Must(template.New(NodeMINUS).Parse("-{{.c1}}")),
 		NodeMINUS + "_2":  template.Must(template.New(NodeMINUS).Parse("{{.c1}} - {{.c2}}")),
@@ -195,11 +196,12 @@ func PrettyPrint(ast *ASTNode) (string, error) {
 				if ast.Children[i].Name == NodeIDENTIFIER {
 					buf.WriteString(".")
 					buf.WriteString(tempParam[fmt.Sprint("c", i+1)])
-				}
-				if ast.Children[i].Name == NodeFUNCCALL {
+				} else if ast.Children[i].Name == NodeFUNCCALL {
 					buf.WriteString("(")
 					buf.WriteString(tempParam[fmt.Sprint("c", i+1)])
 					buf.WriteString(")")
+				} else if ast.Children[i].Name == NodeCOMPACCESS {
+					buf.WriteString(tempParam[fmt.Sprint("c", i+1)])
 				}
 			}