Fix parsing of `with (...) {...}` but still unsupported
This commit is contained in:
parent
a4db488b02
commit
af54a26b43
|
|
@ -2439,7 +2439,8 @@ class AstWith final : public AstNodeExpr {
|
|||
// Children: expression (equation establishing the with)
|
||||
// @astgen op1 := indexArgRefp : AstLambdaArgRef
|
||||
// @astgen op2 := valueArgRefp : AstLambdaArgRef
|
||||
// @astgen op3 := exprp : List[AstNode]
|
||||
// @astgen op3 := exprp : List[AstNode] // Pins, expression and constraints
|
||||
// TODO: Separate expression and constraints
|
||||
public:
|
||||
AstWith(FileLine* fl, AstLambdaArgRef* indexArgRefp, AstLambdaArgRef* valueArgRefp,
|
||||
AstNode* exprp)
|
||||
|
|
@ -2466,12 +2467,15 @@ class AstWithParse final : public AstNodeExpr {
|
|||
// Parents: expr|stmt
|
||||
// Children: funcref, expr
|
||||
// @astgen op1 := funcrefp : AstNodeExpr
|
||||
// @astgen op2 := exprsp : List[AstNode]
|
||||
// @astgen op3 := exprsp : List[AstNode] // With's parenthesis part
|
||||
// @astgen op4 := constraintsp : List[AstNode] // With's braces part
|
||||
public:
|
||||
AstWithParse(FileLine* fl, AstNodeExpr* funcrefp, AstNode* exprsp)
|
||||
AstWithParse(FileLine* fl, AstNodeExpr* funcrefp, AstNode* exprsp,
|
||||
AstNode* constraintsp = nullptr)
|
||||
: ASTGEN_SUPER_WithParse(fl) {
|
||||
this->funcrefp(funcrefp);
|
||||
addExprsp(exprsp);
|
||||
addConstraintsp(constraintsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstWithParse;
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
|
|
|
|||
|
|
@ -1812,12 +1812,24 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
VL_DO_DANGLING(argp->deleteTree(), argp);
|
||||
}
|
||||
// Type depends on the method used, let V3Width figure it out later
|
||||
if (nodep->exprsp()) { // Else empty expression and pretend no "with"
|
||||
if (nodep->exprsp()
|
||||
|| nodep->constraintsp()) { // Else empty expression and pretend no "with"
|
||||
AstNode* exprOrConstraintsp = nullptr;
|
||||
if (nodep->exprsp() && nodep->constraintsp()) {
|
||||
// When support this probably should change AstWith to separate out
|
||||
// the expr from the constraint equation using separate op2/op3 similar
|
||||
// to AstWithParse
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'randomize with (...) {...}'");
|
||||
} else if (nodep->exprsp())
|
||||
exprOrConstraintsp = nodep->exprsp()->unlinkFrBackWithNext();
|
||||
if (nodep->constraintsp())
|
||||
exprOrConstraintsp = AstNode::addNext(
|
||||
exprOrConstraintsp, nodep->constraintsp()->unlinkFrBackWithNext());
|
||||
AstLambdaArgRef* const indexArgRefp
|
||||
= new AstLambdaArgRef{argFl, name + "__DOT__index", true};
|
||||
AstLambdaArgRef* const valueArgRefp = new AstLambdaArgRef{argFl, name, false};
|
||||
AstWith* const newp = new AstWith{nodep->fileline(), indexArgRefp, valueArgRefp,
|
||||
nodep->exprsp()->unlinkFrBackWithNext()};
|
||||
AstWith* const newp
|
||||
= new AstWith{nodep->fileline(), indexArgRefp, valueArgRefp, exprOrConstraintsp};
|
||||
funcrefp->addPinsp(newp);
|
||||
}
|
||||
funcrefp->addPinsp(argp);
|
||||
|
|
|
|||
|
|
@ -533,17 +533,20 @@ size_t V3ParseImp::tokenPipeScanParam(size_t inDepth, bool forCell) {
|
|||
return depth;
|
||||
}
|
||||
|
||||
size_t V3ParseImp::tokenPipeScanTypeEq(size_t depth) {
|
||||
size_t V3ParseImp::tokenPipeScanParens(size_t depth) {
|
||||
// Search around IEEE type_reference to see if is expression
|
||||
// Return location of following token, or input if not found
|
||||
// yTYPE__ETC '(' ... ')' ['==' '===' '!=' '!===']
|
||||
// ^- depth
|
||||
// yRANDOMIZE yWITH '(' ... ')' ['{']
|
||||
// ^- depth
|
||||
if (tokenPeekp(depth)->token != '(') return depth;
|
||||
depth += 1; // Past the (
|
||||
int parens = 1; // Count first (
|
||||
while (true) {
|
||||
const int tok = tokenPeekp(depth)->token;
|
||||
if (tok == 0) { // LCOV_EXCL_BR_LINE
|
||||
UINFO(9, "tokenPipeScanTypeEq hit EOF; probably syntax error to come");
|
||||
UINFO(9, "tokenPipeScanTypeParens hit EOF; probably syntax error to come");
|
||||
break; // LCOV_EXCL_LINE
|
||||
} else if (tok == '(') {
|
||||
++parens;
|
||||
|
|
@ -680,11 +683,11 @@ void V3ParseImp::tokenPipeline() {
|
|||
}
|
||||
} else if (token == yTYPE__LEX) {
|
||||
VL_RESTORER(yylval); // Remember value, as about to read ahead
|
||||
const size_t depth = tokenPipeScanTypeEq(0);
|
||||
const size_t depth = tokenPipeScanParens(0);
|
||||
const int postToken = tokenPeekp(depth)->token;
|
||||
if ( // v-- token v-- postToken
|
||||
// yTYPE__EQ '(' .... ')' EQ_OPERATOR yTYPE_ETC '(' ... ')'
|
||||
postToken == yP_EQUAL || postToken == yP_NOTEQUAL || postToken == yP_CASEEQUAL
|
||||
// v-- token v-- postToken
|
||||
// yTYPE__EQ '(' .... ')' EQ_OPERATOR yTYPE_ETC '(' ... ')'
|
||||
if (postToken == yP_EQUAL || postToken == yP_NOTEQUAL || postToken == yP_CASEEQUAL
|
||||
|| postToken == yP_CASENOTEQUAL) {
|
||||
token = yTYPE__EQ;
|
||||
} else {
|
||||
|
|
@ -704,7 +707,16 @@ void V3ParseImp::tokenPipeline() {
|
|||
}
|
||||
} else if (token == yWITH__LEX) {
|
||||
if (nexttok == '(') {
|
||||
token = yWITH__PAREN;
|
||||
VL_RESTORER(yylval); // Remember value, as about to read ahead
|
||||
const size_t depth = tokenPipeScanParens(0);
|
||||
const int postToken = tokenPeekp(depth)->token;
|
||||
// v-- token v-- postToken
|
||||
// yWITH '(' .... ')' '{'
|
||||
if (postToken == '{') {
|
||||
token = yWITH__PAREN_CUR;
|
||||
} else {
|
||||
token = yWITH__PAREN;
|
||||
}
|
||||
} else if (nexttok == '[') {
|
||||
token = yWITH__BRA;
|
||||
} else if (nexttok == '{') {
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ private:
|
|||
size_t tokenPipeScanIdType(size_t depth) VL_MT_DISABLED;
|
||||
size_t tokenPipeScanBracket(size_t depth) VL_MT_DISABLED;
|
||||
size_t tokenPipeScanParam(size_t depth, bool forInst) VL_MT_DISABLED;
|
||||
size_t tokenPipeScanTypeEq(size_t depth) VL_MT_DISABLED;
|
||||
size_t tokenPipeScanParens(size_t depth) VL_MT_DISABLED;
|
||||
size_t tokenPipeScanEqNew(size_t depth) VL_MT_DISABLED;
|
||||
const V3ParseBisonYYSType* tokenPeekp(size_t depth) VL_MT_DISABLED;
|
||||
void preprocDumps(std::ostream& os, bool forInputs) VL_MT_DISABLED;
|
||||
|
|
|
|||
|
|
@ -6726,11 +6726,13 @@ class WidthVisitor final : public VNVisitor {
|
|||
void visit(AstWith* nodep) override {
|
||||
// Should otherwise be underneath a method call
|
||||
AstNodeDType* const vdtypep = m_vup->dtypeNullSkipRefp();
|
||||
{
|
||||
VL_RESTORER(m_withp);
|
||||
m_withp = nodep;
|
||||
userIterateChildren(nodep->indexArgRefp(), nullptr);
|
||||
userIterateChildren(nodep->valueArgRefp(), nullptr);
|
||||
VL_RESTORER(m_withp);
|
||||
m_withp = nodep;
|
||||
userIterateChildren(nodep->indexArgRefp(), nullptr);
|
||||
userIterateChildren(nodep->valueArgRefp(), nullptr);
|
||||
if (!nodep->exprp()) {
|
||||
nodep->dtypeSetVoid();
|
||||
} else {
|
||||
if (!nodep->exprp()->hasDType()) {
|
||||
userIterateAndNext(nodep->exprp(), nullptr);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -589,6 +589,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
|
|||
%token<fl> yWITH__ETC "with"
|
||||
%token<fl> yWITH__LEX "with-in-lex"
|
||||
%token<fl> yWITH__PAREN "with-then-("
|
||||
%token<fl> yWITH__PAREN_CUR "with-then-(-then-{"
|
||||
%token<fl> yWOR "wor"
|
||||
%token<fl> yWREAL "wreal"
|
||||
%token<fl> yXNOR "xnor"
|
||||
|
|
@ -4052,7 +4053,8 @@ task_subroutine_callNoMethod<nodeExprp>: // function_subroutine_callNoMethod
|
|||
// // IEEE: randomize_call
|
||||
// // We implement randomize as a normal funcRef, since randomize isn't a keyword
|
||||
// // Note yNULL is already part of expressions, so they come for free
|
||||
| funcRef yWITH__CUR constraint_block { $$ = new AstWithParse{$2, $1, $3}; }
|
||||
| funcRef yWITH__CUR constraint_block { $$ = new AstWithParse{$2, $1, nullptr, $3}; }
|
||||
| funcRef yWITH__PAREN_CUR '(' expr ')' constraint_block { $$ = new AstWithParse{$2, $1, $4, $6}; }
|
||||
;
|
||||
|
||||
function_subroutine_callNoMethod<nodeExprp>: // IEEE: function_subroutine_call (as function)
|
||||
|
|
@ -4067,7 +4069,8 @@ function_subroutine_callNoMethod<nodeExprp>: // IEEE: function_subroutine
|
|||
// // IEEE: randomize_call
|
||||
// // We implement randomize as a normal funcRef, since randomize isn't a keyword
|
||||
// // Note yNULL is already part of expressions, so they come for free
|
||||
| funcRef yWITH__CUR constraint_block { $$ = new AstWithParse{$2, $1, $3}; }
|
||||
| funcRef yWITH__CUR constraint_block { $$ = new AstWithParse{$2, $1, nullptr, $3}; }
|
||||
| funcRef yWITH__PAREN_CUR '(' expr ')' constraint_block { $$ = new AstWithParse{$2, $1, $4, $6}; }
|
||||
;
|
||||
|
||||
system_t_call<nodeStmtp>: // IEEE: system_tf_call (as task)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
%Error-UNSUPPORTED: t/t_randomize_with_constraint.v:13:26: Unsupported: 'randomize with (...) {...}'
|
||||
13 | return obj.randomize() with (
|
||||
| ^~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error-UNSUPPORTED: t/t_randomize_with_constraint.v:21:26: Unsupported: 'randomize with (...) {...}'
|
||||
21 | return obj.randomize() with (
|
||||
| ^~~~
|
||||
%Error: Exiting due to
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.lint(fails=True, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class Cls;
|
||||
rand int m_x;
|
||||
int m_y = -1;
|
||||
endclass
|
||||
|
||||
function int func1(Cls obj, int y);
|
||||
return obj.randomize() with (
|
||||
m_x) {
|
||||
m_x > 0;
|
||||
m_x < y;
|
||||
};
|
||||
endfunction
|
||||
|
||||
function int func2(Cls obj, int y);
|
||||
return obj.randomize() with (
|
||||
m_x) {
|
||||
m_x > 0;
|
||||
m_x < m_y;
|
||||
};
|
||||
endfunction
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
Cls c;
|
||||
int i;
|
||||
c = new;
|
||||
i = func1(c, 2);
|
||||
i = func2(c, 2);
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue