Repository: Nic30/hdlConvertor (language: python)

Issue:
`Conversion to Python object not implemented` Error from Primitive Structural Verilog Code
HdlConvertor seems to throw and warning and not successfully parse structural verilog code.

The problem seems to appear in statements such as:

```verilog
and a1 (tmp, a, b);
```

This is defined to be valid in IEEE 1800-2017, Section 28.4 "and, nand, nor, or, xor, and xnor gates" (page 803?)

> The instance declaration of a multiple input logic gate shall begin with one of the following keywords:
> `and nand nor or xor xnor`
> The delay specification shall be zero, one, or two delays. If the specification contains two delays, the first delay shall determine the output rise delay, the second delay shall determine the output fall delay, and the smaller of the two delays shall apply to output transitions to x. If only one delay is specified, it shall specify both the rise delay and the fall delay. If there is no delay specification, there shall be no propagation delay through the gate.

## Steps to Reproduce

An example code that will demonstrate the issue.
```verilog
module example (a, b, c, d);
input a, b, c;
output d;

wire tmp;
and a1 (tmp, a, b);
or o1 (d, tmp, d);
endmodule
```

This can then be loaded and run with this Python code.
```python
from hdlConvertorAst.language import Language
from hdlConvertor import HdlConvertor

c = HdlConvertor()
d = c.parse(["example.v"], Language.VERILOG, [], hierarchyOnly=False, debug=True)
```

This shows the error message:
```
example.v:5:4: VerGateParser.visitGate_instantiation Conversion to Python object not implemented
    ...anda1(tmp,a,b);...
example.v:6:4: VerGateParser.visitGate_instantiation Conversion to Python object not implemented
    ...oro1(d,tmp,d);...
```

The parsed value can be returned by running this Python code:
```python
from hdlConvertorAst.to.verilog.verilog2005 import ToVerilog2005

tv = ToVerilog2005(sys.stdout)
tv.visit_HdlContext(d)
```

Which prints the coverted Verilog code.

```verilog
module example (
    input wire A,
    input wire B,
    input wire C,
    output wire D
);
    wire TMP;
endmodule
```

The `and` and `or` definitions are now missing.

By looking at the JSON, it seems the assignments are missing from parsed output.

```python
from hdlConvertorAst.to.json import ToJson
import json
tj = ToJson()
j = tj.visit_HdlContext(d)
print(json.dumps(j[0]["objs"], sort_keys=True,indent=4))
```

You can see the `tmp` declaration, but there is nothing else here.
This is where I expect the assignment to be (I'm new, I could be wrong).

```
[
    {
        "__class__": "HdlIdDef",
        "direction": "INTERNAL",
        "name": {
            "__class__": "str",
            "val": "TMP"
        },
        "position": [
            5,
            6,
            5,
            8
        ],
        "type": {
            "__class__": "HdlTypeAuto"
        }
    }
]
```

I trying to analyze some Verilog code, and unfortunate this issue is preventing the analysis from working correctly.
hdlConvertor was installed via pip3 on Ubuntu.
`Conversion to Python object not implemented` Error from Primitive Structural Verilog Code
HdlConvertor seems to throw and warning and not successfully parse structural verilog code.

The problem seems to appear in statements such as:

```verilog
and a1 (tmp, a, b);
```

This is defined to be valid in IEEE 1800-2017, Section 28.4 "and, nand, nor, or, xor, and xnor gates" (page 803?)

> The instance declaration of a multiple input logic gate shall begin with one of the following keywords:
> `and nand nor or xor xnor`
> The delay specification shall be zero, one, or two delays. If the specification contains two delays, the first delay shall determine the output rise delay, the second delay shall determine the output fall delay, and the smaller of the two delays shall apply to output transitions to x. If only one delay is specified, it shall specify both the rise delay and the fall delay. If there is no delay specification, there shall be no propagation delay through the gate.

## Steps to Reproduce

An example code that will demonstrate the issue.
```verilog
module example (a, b, c, d);
input a, b, c;
output d;

wire tmp;
and a1 (tmp, a, b);
or o1 (d, tmp, d);
endmodule
```

This can then be loaded and run with this Python code.
```python
from hdlConvertorAst.language import Language
from hdlConvertor import HdlConvertor

c = HdlConvertor()
d = c.parse(["example.v"], Language.VERILOG, [], hierarchyOnly=False, debug=True)
```

This shows the error message:
```
example.v:5:4: VerGateParser.visitGate_instantiation Conversion to Python object not implemented
    ...anda1(tmp,a,b);...
example.v:6:4: VerGateParser.visitGate_instantiation Conversion to Python object not implemented
    ...oro1(d,tmp,d);...
```

The parsed value can be returned by running this Python code:
```python
from hdlConvertorAst.to.verilog.verilog2005 import ToVerilog2005

tv = ToVerilog2005(sys.stdout)
tv.visit_HdlContext(d)
```

Which prints the coverted Verilog code.

```verilog
module example (
    input wire A,
    input wire B,
    input wire C,
    output wire D
);
    wire TMP;
endmodule
```

The `and` and `or` definitions are now missing.

By looking at the JSON, it seems the assignments are missing from parsed output.

```python
from hdlConvertorAst.to.json import ToJson
import json
tj = ToJson()
j = tj.visit_HdlContext(d)
print(json.dumps(j[0]["objs"], sort_keys=True,indent=4))
```

You can see the `tmp` declaration, but there is nothing else here.
This is where I expect the assignment to be (I'm new, I could be wrong).

```
[
    {
        "__class__": "HdlIdDef",
        "direction": "INTERNAL",
        "name": {
            "__class__": "str",
            "val": "TMP"
        },
        "position": [
            5,
            6,
            5,
            8
        ],
        "type": {
            "__class__": "HdlTypeAuto"
        }
    }
]
```

I trying to analyze some Verilog code, and unfortunate this issue is preventing the analysis from working correctly.
hdlConvertor was installed via pip3 on Ubuntu.


Discussion / hints:
@Nic30 , any comment on how to handle this?
@Nic30 , any comment on how to handle this?

Fix patch:
diff --git a/.gitignore b/.gitignore
index 8c7939fa..fc711135 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,3 +65,5 @@ grammars/.idea
 coverage.info
 coverage.info.raw
 
+# Ignore .vscode files
+.vscode/
\ No newline at end of file
diff --git a/include/hdlConvertor/svConvertor/gateParser.h b/include/hdlConvertor/svConvertor/gateParser.h
index cf06dabc..be8b4c70 100644
--- a/include/hdlConvertor/svConvertor/gateParser.h
+++ b/include/hdlConvertor/svConvertor/gateParser.h
@@ -23,10 +23,14 @@ class VerGateParser: public BaseSvParser {
 			sv2017Parser::Output_terminalContext *ctx);
 	hdlAst::HdlOpType visitN_output_gatetype(
 			sv2017Parser::N_output_gatetypeContext *ctx);
+	hdlAst::HdlOpType visitN_input_gatetype(
+			sv2017Parser::N_input_gatetypeContext *ctx);
 	// @return <output, input>
 	std::pair<std::unique_ptr<hdlAst::iHdlExprItem>,
 			std::unique_ptr<hdlAst::iHdlExprItem>> visitN_output_gate_instance(
 			sv2017Parser::N_output_gate_instanceContext *ctx);
+	std::vector<std::unique_ptr<hdlAst::iHdlExprItem>> visitN_input_gate_instance(
+			sv2017Parser::N_input_gate_instanceContext *ctx);
 	void visitGate_instantiation(sv2017Parser::Gate_instantiationContext *ctx,
 			std::vector<std::unique_ptr<hdlAst::iHdlObj>> &res);
 };
diff --git a/pyproject.toml b/pyproject.toml
index 4968120b..cc13dff9 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,2 +1,3 @@
 [build-system]
 requires = ["setuptools", "wheel", "scikit-build", "Cython", "cmake", "ninja"]
+build-backend = "setuptools.build_meta"
diff --git a/src/svConvertor/gateParser.cpp b/src/svConvertor/gateParser.cpp
index f959adcc..ba857536 100644
--- a/src/svConvertor/gateParser.cpp
+++ b/src/svConvertor/gateParser.cpp
@@ -4,8 +4,9 @@
 #include <hdlConvertor/hdlAst/hdlStmAssign.h>
 #include <hdlConvertor/createObject.h>
 #include <hdlConvertor/notImplementedLogger.h>
+#include <hdlConvertor/hdlAst/hdlCompInst.h>
 
-#include <assert.h>
+#include <cassert>
 
 
 namespace hdlConvertor {
@@ -52,6 +53,37 @@ HdlOpType VerGateParser::visitN_output_gatetype(
 	}
 }
 
+HdlOpType VerGateParser::visitN_input_gatetype(
+		sv2017Parser::N_input_gatetypeContext *ctx) {
+	// n_input_gatetype:
+	// KW_AND
+	// | KW_NAND
+	// | KW_OR
+	// | KW_NOR
+	// | KW_XOR
+	// | KW_XNOR
+	// ;
+	if(ctx->KW_AND()) {
+		return HdlOpType::AND;
+	}
+	if (ctx->KW_NAND()) {
+		return HdlOpType::NAND;
+	}
+	if (ctx->KW_OR()) {
+		return HdlOpType::OR;
+	}
+	if (ctx->KW_NOR()) {
+		return HdlOpType::NOR;
+	}
+	if (ctx->KW_XOR()) {
+		return HdlOpType::XOR;
+	}
+	assert(ctx->KW_XNOR());
+	{
+		return HdlOpType::XNOR;
+	}
+}
+
 std::pair<std::unique_ptr<iHdlExprItem>, std::unique_ptr<iHdlExprItem>> VerGateParser::visitN_output_gate_instance(
 		sv2017Parser::N_output_gate_instanceContext *ctx) {
 	// n_output_gate_instance:
@@ -79,6 +111,27 @@ std::pair<std::unique_ptr<iHdlExprItem>, std::unique_ptr<iHdlExprItem>> VerGateP
 	}
 }
 
+std::vector<std::unique_ptr<iHdlExprItem>> VerGateParser::visitN_input_gate_instance(
+		sv2017Parser::N_input_gate_instanceContext *ctx) {
+	// n_input_gate_instance:
+	// ( name_of_instance )? LPAREN output_terminal ( COMMA input_terminal )+ RPAREN;
+	auto noi = ctx->name_of_instance();
+	if (noi) {
+		// name_of_instance: identifier ( unpacked_dimension )*;
+		// auto name = VerExprParser::visitIdentifier(noi->identifier());
+		NotImplementedLogger::print(
+				"VerGateParser.visitN_input_gate_instance name_of_instance",
+				ctx);
+	}
+	auto _ot = ctx->output_terminal();
+	vector<unique_ptr<iHdlExprItem>> terminals;
+	terminals.emplace_back(visitOutput_terminal(_ot));
+	for(auto _it : ctx->input_terminal()) {
+		terminals.emplace_back(visitInput_terminal(_it));
+	}
+	return terminals;
+}
+
 void VerGateParser::visitGate_instantiation(
 		sv2017Parser::Gate_instantiationContext *ctx,
 		std::vector<std::unique_ptr<hdlAst::iHdlObj>> &res) {
@@ -123,6 +176,65 @@ void VerGateParser::visitGate_instantiation(
 			}
 			res.push_back(move(a));
 		}
+	} else if (auto _ot2 = ctx->n_input_gatetype()) {
+		auto ot = visitN_input_gatetype(_ot2);
+		auto ds = ctx->drive_strength();
+		if (ds) {
+			NotImplementedLogger::print(
+					"VerGateParser.visitGate_instantiation drive_strength",
+					ctx);
+		}
+		auto d2 = ctx->delay2();
+		if (d2) {
+			NotImplementedLogger::print(
+					"VerGateParser.visitGate_instantiation delay2", ctx);
+		}
+		for (auto ogi : ctx->n_input_gate_instance()) {
+			unique_ptr<HdlCompInst> a;
+			auto output_input = visitN_input_gate_instance(ogi);
+			//
+			// n_input_gatetype:
+			// KW_AND
+			// | KW_NAND
+			// | KW_OR
+			// | KW_NOR
+			// | KW_XOR
+			// | KW_XNOR
+			// ;
+			auto noi = ogi->name_of_instance();
+			auto name = (noi)?VerExprParser::visitIdentifier(noi->identifier()): make_unique<HdlValueId>(" ");
+			std::unique_ptr<HdlValueId> gt;
+			switch(ot) {
+				case HdlOpType::AND:
+					gt = create_object<HdlValueId>(ogi, "and");
+				break;
+				case HdlOpType::NAND:
+					gt = create_object<HdlValueId>(ogi, "nand");
+				break;
+				case HdlOpType::OR:
+					gt = create_object<HdlValueId>(ogi, "or");
+				break;
+				case HdlOpType::NOR:
+					gt = create_object<HdlValueId>(ogi, "nor");
+				break;
+				case HdlOpType::XOR:
+					gt = create_object<HdlValueId>(ogi, "xor");
+				break;
+				case HdlOpType::XNOR:
+					gt = create_object<HdlValueId>(ogi, "xnor");
+				break;
+				default:
+					// Should not reach here!
+					assert(false);
+				break;
+			}
+			if (gt) {
+				a = create_object<HdlCompInst>(ogi, move(name), move(gt));
+				a->portMap = move(output_input);
+			}
+			if(a)
+				res.push_back(move(a));
+		}
 	} else {
 		NotImplementedLogger::print("VerGateParser.visitGate_instantiation",
 				ctx);


Test patch:
diff --git a/tests/test_verilog_conversion.py b/tests/test_verilog_conversion.py
index c8107860..6f72b687 100644
--- a/tests/test_verilog_conversion.py
+++ b/tests/test_verilog_conversion.py
@@ -142,6 +142,9 @@ def test_stm_import(self):
     def test_function_non_ansi(self):
         self.parseWithRef("function_non_ansi.v", VERILOG)
 
+    def test_verilog_primitives(self):
+        self.parseWithRef("test_verilog_primitives.v", VERILOG)
+
 
 
 if __name__ == "__main__":
diff --git a/tests/verilog/expected/test_verilog_primitives.v b/tests/verilog/expected/test_verilog_primitives.v
new file mode 100644
index 00000000..9c54578d
--- /dev/null
+++ b/tests/verilog/expected/test_verilog_primitives.v
@@ -0,0 +1,47 @@
+// Test Scenario to validate correct translation
+// Refer: https://github.com/Nic30/hdlConvertor/issues/173
+module dummy (
+    output wire c,
+    input wire a,
+    input wire b
+);
+    and a1 (
+        c,
+        a,
+        b
+    );
+
+endmodule
+module d2 (
+    output wire y,
+    input wire a
+);
+    assign y = ~a;
+endmodule
+module example (
+    input wire a,
+    input wire b,
+    input wire c,
+    output wire d
+);
+    wire tmp;
+    wire tmp2;
+    and a1 (
+        tmp,
+        a,
+        b
+    );
+
+    dummy du (
+        tmp2,
+        b,
+        c
+    );
+
+    or o1 (
+        d,
+        tmp,
+        tmp2
+    );
+
+endmodule
diff --git a/tests/verilog/test_verilog_primitives.v b/tests/verilog/test_verilog_primitives.v
new file mode 100644
index 00000000..870f3ff7
--- /dev/null
+++ b/tests/verilog/test_verilog_primitives.v
@@ -0,0 +1,26 @@
+// Test Scenario to validate correct translation
+// Refer: https://github.com/Nic30/hdlConvertor/issues/173
+
+module dummy(c, a, b);
+output c;
+input a, b;
+and a1(c, a, b);
+endmodule
+
+module d2(y, a);
+output y;
+input a;
+
+not n1 (y, a);
+endmodule
+
+module example (a, b, c, d);
+input a, b, c;
+output d;
+
+wire tmp;
+wire tmp2;
+and a1 (tmp, a, b);
+dummy du(tmp2, b, c);
+or o1 (d, tmp, tmp2);
+endmodule