# What Bluespec Borrowed From Haskell

Bluespec System Verilog reads like Haskell on purpose, and building IDE support for it meant reusing Haskell's own grammar, keywords and all.


Bluespec System Verilog reads like Haskell because it is, structurally, Haskell wearing a hardware costume. That is not a coincidence and it is not a gimmick someone bolted on to look clever. It is a real design choice with a real consequence, and I ran into that consequence directly while building Bluespec support into Flexible Haskell.
Rules instead of always-blocks Write Verilog and you describe hardware behavior with always-blocks: procedural code triggered on a clock edge, and the burden of proving nothing collides sits entirely on you. Two blocks touching the same register in the same cycle is your bug to find, by hand, usually late.
Bluespec expresses behavior differently. Instead of always-blocks it has Rules, guarded atomic actions: a condition and an action, and interface methods are themselves built from rule fragments. You are not scheduling anything yourself. The compiler looks at the whole set of rules, works out which ones can fire together and which conflict, and compiles the result down to synchronous clocked Verilog RTL you can hand to any normal synthesis tool. The scheduling problem does not go away. It just stops being your problem to solve by hand every time.
That is a genuinely different way to think about describing hardware, and the syntax it borrowed to express it is Haskell’s.
One grammar, two languages, one honest gap Flexible Haskell keeps a single BNF grammar for Haskell itself, generated into a real parser and PSI tree. Bluespec Classic, the .bs file extension, does not get its own grammar. BluespecParserDefinition extends HaskellParserDefinition directly and only swaps in a different lexer. The parser, the actual generated class that builds the syntax tree, is the exact same one Haskell uses.
The lexer is where the real trick sits. BluespecLexerAdapter wraps the identical JFlex-generated Haskell lexer and inspects every VARID token, an ordinary lowercase identifier, asking whether it happens to be one of a specific list: action, interface, letseq, package, primitive, rules, signature, struct, stringOf, synthesize, valueOf, verilog, when, coherent, incoherent. If it matches, it gets reclassified into a Bluespec keyword token on the spot. Everything else stays exactly as Haskell would have lexed it.
I went looking through that list again while writing this and noticed something I had not caught before: rule, the word you write constantly for a single named rule, is not on it. Only its plural, rules, the block keyword that groups several rules together, made the cut. I have no memory of deciding to leave the singular out. It just never got added, and nothing in months of testing surfaced it, because a missing keyword highlight is not the kind of bug that throws an error at you.
Bluespec SystemVerilog, the .bsv extension, does not share any of this. BluespecSVParserDefinition does not extend the Haskell definition at all. It has its own lexer and its own parser, and the parser is deliberately trivial: it advances through every token until end of file and wraps the whole thing in one flat node. No real syntax tree, no composite PSI elements, nothing structural to break.
What sharing a parser actually costs Here is the part that is easy to say and easy to underestimate: Haskell and Bluespec Classic share the exact same generated parser class. Fix an edge case in how the grammar handles Haskell’s layout rule, the offside rule that decides where a block implicitly ends, and you have just changed how every .bs file in existence gets parsed, whether you tested that or not. There is no separate Bluespec grammar to change in isolation. There is one generated class serving two languages that only sometimes agree with each other, and a fix aimed at one is a shot fired at both.
rule incrementCounter (state == Running); counter <= counter + 1; endrule That is ordinary Bluespec. It will lex and highlight fine today. It does so despite a keyword gap I only just found, because the shared grammar happened to route around it, not because anyone verified the whole keyword set against the language spec line by line.
Bluespec Classic gets Haskell’s grammar for free by design, and that is a genuinely elegant trick when it works. Bluespec SystemVerilog opted out of the whole arrangement with its own lexer and its own do-nothing parser, and after finding the missing rule keyword sitting quietly in the shared one, I understand exactly why that looked like the safer choice.
Flexible Haskell is on the JetBrains Marketplace. It is still a young plugin, and if you write Bluespec and find a keyword that is not highlighted, you now know roughly why.
