Petal compiler, specification, and tools 3.1KB

Petal style guide

It is easier to read and write code written in a consistent style. Here are guidelines for how to write Petal in the canonical way.


Type names should be PascalCase and all other identifiers should be snake_case.

Short initialisms / acronyms should be capitalized in type names. Initialisms of five or more characters should be treated as a word. For instance:

# These are short acronyms, so they're capitalized.
struct URI {}
enum HTTPStatusCode {}
# But "NPAPI" is too long, so it's a word.
class NpapiWrapper {}

A type intended to be a drop-in replacement for a builtin type, or to serve a similar role, should be lowercase, without underscores.

# Good: Like string, but encoded in utf16.
struct wstring { let uint16[] data. }
# Good: Rational numbers that can be used similarly to float.
struct rational64 { let int64 num = 0.  let int64 denom = 0. }
# Bad: test cases don't mimic a builtin type, and builtins don't behave like classes.
class testcase { let string name. let (unit -> unit) fn. }

You MAY violate these rules to bind to an external library to make porting easier, but it is recommended to use the Petal style.


Indentation and newlines

Use two spaces to indent. Do not try to align code with tabs or spaces.

Try to limit column width to 80 characters. This lets someone using a moderately large font to fit two columns of code comfortably on a 1920x1200 screen.

Opening curly brackets { go on the same line as the thing they belong to. Short blocks can be written on the same line; blocks containing more than one statement should almost always have a line for each.

if some_condition { print "equal!". }
if 1 == 2 { print "equal!". }

Use the Rectangle Rule to determine how to lay out your code: you should be able to draw a rectangle around each independent piece of code that doesn’t intersect with anything else (ignoring brackets).

When indenting a continuation of a previous line, double-indent. This better distinguishes the continuation from a subsequent indent.

# Bad: the argument list is an independent piece of code, but its rectangle
# intersects with the parent's name.
funcWithLotsOfArgs int32 a, string b,
    int64 c, MyType d -> int32 {
  return 0.
# Good: all in one line means nothing intersects
funcWithLotsOfArgs int32 a, string b, int64 c, MyType d -> int32 {}
# Good: multiple lines without intersect
    int32 a, string b,
    int64 c, MyType d -> int32 {
  return 0.

Operators should have spaces around them.

# Good
return 1 + 3 * 2.
# Bad: inconsistent and misleading
return 1+3 * 2.
# Bad: everything's squished together and harder to read
return 1+3*2.

Curly braces should have spaces between them and any other symbol:

# Good
if 1 == 2 { println "Math is broken". } else { println "Safe!". }
# Bad
if 1 == 2{println "Math is broken".}else{println "Safe!".}

Short flow control statements can be all on one line, as above.

You can’t omit the curly braces; that simply won’t compile.