Contributing to B2R2
August 19, 2025 ยท View on GitHub
Thank you for taking your time to contribute to B2R2! :+1: Please read this guideline before creating a PR (Pull Request) or an issue.
Git Commit Messages
We follow the convention described in this article.
- Split the subject line and the body (if needed).
- Start the subject line with a capital letter.
- Do not use a period at the end of the subject line.
- The body is optional: subject-only commit is okay.
- The body should explain why you made this commit.
- The subject line is limited to maximum 50 characters.
- Each line in the body is limited to maximum 72 characters.
In addition to the above rules, we prepend a tag to the subject line. A tag is basically a word within a pair of square brackets. For example, you may consider using the following tags:
- [Intel]: when the commit is about Intel module.
- [ARMv7]: when the commit is about ARMv7 module.
- [ARMv8]: when the commit is about ARMv8 module.
- [MIPS]: when the commit is about MIPS module.
- [Build]: when the commit is about the build system.
- [IR]: when the commit is about the IR.
- [WebUI]: when the commit is about the WebUI.
- [ELF]: when the commit is about the ELF binaries.
- [PE]: when the commit is about the PE binaries.
- [Mach]: when the commit is about the Mach binaries.
- [Doc]: when the commit is about documentation.
- [CI]: when the commit is about continuous integration.
- [Test]: when the commit is about our unittest modules.
F# Coding Style
Please read the F# code formatting guideline, before you proceed as we mostly follow it.
Basic Rules
- Width = 80: We strictly limit the code width to be 80.
- No tabs: We do not use
tabfor spacing. - Indentation = 2: We always use two space characters for indentations.
Comments
- We use two styles for comments: documentation, and non-documentation comments
- Documentation comments are for documenting the code (and for IntelliSense). All these comments will be stored in XML files for IntelliSense.
- Documentation comments start with triple slashes:
/// Your comment. - Documentation comments should be above the code
- Non-documentation comments are ordinary comments
- Non-documentation comments are put in between
(*and*)
Naming
- We use nouns for variables (or parameters).
- We mostly use verbs for function names.
Line-endings
We always use unix-style (LF) line-endings for every file.
Editor Settings
-
See our .editorconfig
-
For Emacs users:
(setq-default fsharp-indent-offset 2) -
For Vim users:
autocmd FileType fsharp setlocal softtabstop=2 autocmd FileType fsharp setlocal shiftwidth=2 autocmd FileType fsharp setlocal textwidth=80
Specific Rules
Argument Assignments
When using the equality operator (=):
let func = value // Good
if foo = bar then // Good
let func=value // Bad
if foo=bar then // Bad
When using (=) for argument assignments:
Func(param = argu) // Good
| Func(pattern = bound) // Good
let func (param = bound) = // Good
Func(param=argu) // Bad
| Func(pattern= bound) // Bad
let func (param =bound) = // Bad
Tuple Constructs
When writing tuples, use consistent spacing between elements. Do not omit spaces or add inconsistent spacing.
1, 2, 3 // Good
1,2,3 // Bad
1, 2, 3 // Bad
Parentheses Constructs
When writing parentheses, apply clean formatting without unnecessary spaces.
() // Good
( ) // Bad
(elements) // Good
( elements ) // Bad
List/Array Literals
We prefer to have space chars for list/array literals. For example,
[ 1; 2; 3 ] // Good
[1; 2; 3] // Bad
For arrays, the same spacing rules apply:
[| 1; 2; 3 |] // Good
[|1; 2; 3|] // Bad
When we use a range operator:
[ 1 .. 10 ] // Good
[1 .. 10] // Bad
[ 1..10 ] // Bad
Element spacing must be exactly one space after semicolons:
[ 1; 2; 3 ] // Good
[ 1;2; 3 ] // Bad
[ 1; 2; 3 ] // Bad
When there is no element:
[] // Good
[ ] // Bad
For nested literals, outer containers have internal spacing:
[ [ 1; 2 ]; [ 3; 4 ] ] // Good
[[ 1; 2 ]; [ 3; 4 ]] // Bad
For multiline literals, prefer single-line unless exceeding 80 characters:
let good = [ elements ]
When multiline format is required, use only this structure:
let good =
[ element
element ]
When pattern matching on a list:
match lst with
| e1 :: [] -> ...
| e1 :: e2 :: [] -> ...
Indexed Property
When using indexed property, we prefer bracket notation for accessing elements:
src[0] <- Const // Good
src[ 0 ] <- Const // Bad
src.Item(0) <- Const // Bad
For array/list indexing and slicing, we do not use spaces inside brackets:
src[1] // Good
src[1..3] // Good
src[1..] // Good
src[..3] // Good
src[1..2..10] // Good
src[ 1 ] // Bad
src[ 1 .. 3 ] // Bad
src[ 1 .. ] // Bad
src[ .. 3 ] // Bad
src[ 1 .. 2 .. 10 ] // Bad
Type Annotation
We prefer to have a space character between a colon/star and a type name. For example,
let fn (p: int) = ... // Good
type X = X of a: int * b: int // Good
let x (x: int[]) = x // Good
let y (y: int * int) = y // Good
let fn (x: int -> string) = x // Good
let fn (p:int) = ... // Bad
type X = X of a:int * b :int // Bad
let x (x: int []) = x // Bad
let y (y: int*int) = y // Bad
let fn (x: int->string) = x // Bad
Generic Type Argument
When writing generic type arguments, do not include spaces between brackets
func<type> // Good
func< type > // Bad
When using tuple types inside generic type arguments, use it as shown below.
func<type1, type2> // Good
func<type1 * type2> // Good
func<type1,type2> // Bad
func<type1*type2> // Bad
When generic type arguments are followed by parentheses, use it as shown below.
Func<'T>() // Good
List<int>() // Good
Dictionary<string, int>() // Good
Func<'T> () // Bad
List<int> () // Bad
Dictionary<string, int> () // Bad
Records
We define a record as follows.
type InsSize =
{ MemSize: MemorySize
RegSize: RegType
OperationSize: RegType
SizeCond: OperandsSizeCondition } // Good
type InsSize =
{
MemSize: MemorySize
RegSize: RegType
OperationSize: RegType // Bad
SizeCond: OperandsSizeCondition // Bad
}
{ Prefixes = prefs } // Good
{Prefixes = prefs} // Bad
{ Prefixes = prefs
Opcode = opcode } // Good
{
Prefixes = prefs
Opcode = opcode
} // Bad
{ Prefixes = prefs } // Good
{ Prefixes= prefs } // Bad
{ Prefixes = prefs; Opcode = opcode } // Good
{ Prefixes = prefs;Opcode = opcode } // Bad
Function Body
Avoid using an empty newline in the function body. People often use an empty newline in the function body to separate logical blocks. One may think that this is better for readability, but using an empty newline in the function body implies that the function is already too long. You should instead refactor the function into smaller functions.
let fn p =
let x = foo p
let y = foo p
let z = x + y // Good
let fn p =
(* omitted complex logic *)
let x = (* something *)
(* omitted complex logic *)
let y = (* something *)
let z = x + y // Bad
When defining mutual recursive functions, place exactly one empty newline between let rec and and declarations.
let rec isEven n =
if n = 0 then true
else isOdd (n - 1)
and isOdd n =
if n = 0 then false
else isEven (n - 1) // Good
let rec isEven n =
if n = 0 then true
else isOdd (n - 1)
and isOdd n =
if n = 0 then false
else isEven (n - 1) // Bad
let nested () =
let rec isEven n =
if n = 0 then true
else isOdd (n - 1)
and isOdd n =
if n = 0 then false
else isEven (n - 1)
isEven 10 // Bad
Declarations
For top-level bindings, separate them with exactly one empty line:
let foo = 1
let bar = 2 // Good
let foo = 1
let bar = 2 // Bad
let foo = 1
let bar = 2 // Bad
Function Calls
When calling a non-curried function, we use the following style:
Func(p1, p2, p3) // Good
Func (p1, p2, p3) // Bad
When the method name starts with an uppercase, write it without a space after the dot to support chain calls. When it starts with a lowercase, add a space to follow curried function style.
String.Replace() // Good
String.replace () // Good
String.Replace () // Bad
String.replace() // Bad
Someone may say that it is covenient to not use any space character between the function name and the parameters, especially when the function is not F#-style (curried) functions. For example, it allows us to chain multiple member calls as below.
str.Replace("A", "B").Replace("C", "D") // It is easy to chain calls.
However, we still do not recommend this style because this is more suited for OOP languages such as C#, but not for F#. We still allow this style when you call a chain of member functions though.
Pattern Matching Constructs
There must be exactly one space between the match expression and the with keyword.
match x with // Good
| Foo -> Some good
| Bar -> None
match x with // Bad
| Foo -> Some bad
| Bar -> None
The match and with keywords must be on the same line.
match x with // Good
| Foo -> Some good
| Bar -> None
match x // Bad
with
| Foo -> Some bad
| Bar -> None
The pipe (|) and the pattern must be on the same line.
match x with // Good
| Foo -> Some good
| Bar -> None
match x with // Good
| Foo | Bar -> Some good
match x with // Bad
| Foo |
Bar -> Some bad
Each pipe (|) must be aligned vertically with the match keyword.
match x with // Good
| Foo -> Some good
| Bar -> None
match x with // Bad
| Foo -> Some bad
| Bar -> None
There must be a space after the pipe (|).
match x with // Good
| Foo -> Some good
| Bar -> None
match x with // Bad
|Foo -> Some bad
|Bar -> None
When there are elements on both sides of '->', spaces are required on the side with elements.
match x with // Good
| Foo -> Some good
| Bar -> None
match x with // Bad
| Foo-> Some bad
| Bar ->None
Class and Member Definition
We prefer to define classes with a space character between the name and the parentheses.
type Class() = // Good
type Class () = // Bad
For classes with access modifiers, the access modifier should be placed directly before the parentheses without a space.
type GenericClass<'T> private() = // Good
type GenericClass<'T> private () = // Bad
When defining auxiliary constructors using new, we use the following style.
new(value) = Class(value) // Good
new (value) = Class(value) // Bad
When defining properties using with, we use the following style.
member _.Method with get() = value and set(value) = value // Good
member _.Method with get () = value and set (value) = value // Bad
When function name is LowerCase, use a space before parentheses. and function name is PascalCase, attach the parentheses to the function name.
member _.Method() = value // Good
static member Method() = value // Good
static member method () = value // Good
member _.Method () = value // Bad
static member Method () = value // Bad
static member method() = value // Bad
Member functions should always use non-curried style with parentheses when there are multiple parameters. Single parameters can omit parentheses.
member _.Add(x, y) = x + y // Good
member _.Square(x) = x * x // Good
static member Create(value) = Calculator() // Good
static member Create value = Calculator() // Good
member _.Add x y = x + y // Bad
member _.Square (x) = x * x // Bad
We use this for a self-identifier when we need to use it. However, for other
cases, we use a single underscore _ to consistently indicate that we do not
need to use it. We avoid using __ for a self-identifier because it is less
readable.
type Class() =
member this.A(p1, p2) = this.Foo p1 // Good
member _.A(p1, p2) = Foo p1 // Good
type Class() =
member this.A(p1, p2) = Foo p1 // Bad
member __.A(p1, p2) = __.Foo p1 // Bad
JavaScript & CSS Coding Style
We use camlCase for JavaScript, and BEM (Block, Element, and Modifier) for CSS.
Specifically, we follow styles suggested from
https://www.w3schools.com/js/js_conventions.asp and http://getbem.com/naming/.
Additionally, we use js- prefix for IDs of DOM objects, when they are used in
JavaScript.