Skip to content

Pragmas Error Emissions

ike709 edited this page Mar 9, 2024 · 15 revisions

#pragma - OpenDream error emission configuration

Through the #pragma directive, the errors and warnings emitted by OD can be configured to suit your codebase.

For the current default pragma settings and an up-to-date list of all pragmas, see here

Parity vs. Sanity

There are many undocumented, strange behaviours within the BYOND implementation of DM and its engine. This project aims to replicate this behaviour as best as we can, in order to maximize your ability to migrate onto our software.

However, much of this behaviour results in code operating in a way that is not what the programmer intended, and not all codebases require all the cursed behaviour in order to successfully run. This creates a design problem: Do we prefer creating an engine that prioritizes parity over sanity, or sanity over parity?

The answer, is "both." Many of the possible errors emittable by the compiler can be enabled or disabled arbitrarily through #pragma directives:

#pragma ErrorDirective warning // Turns #error directives into simple warnings
#error "*deathgasp" // This only creates a warning on-compile.

Every possible warning has a name and a code, and can be referenced either way within one of these directives.

The default configuration file is aimed at providing a reasonable version of DM, balancing parity and sanity. Only behaviour that is clearly unintentional is raised as an error. Configuration files for builds that prefer parity, or prefer sanity, are coming soon:tm:.


The following is a (hopefully!) exhaustive list of every error code and its use. If it is incomplete, you can help by expanding it.

Fatal Errors (0000 - 0999)

Errors with codes less than 1000 are fatal. They cannot be disabled through #pragma directives. Errors of this genre usually are fundamental errors in the grammar of the source code given, making reasonable compilation impossible. In C++ lingo, any code that hits one of these errors is "ill-formed."

0000 - Unknown

This code is the default for errors which have yet to be assigned a proper error code. They are always fatal, and the only information available is the error message you receive upon this error occurring.

0001 - BadToken

This code is emitted when an unexpected Token is reached.

0010 - BadDirective

This is emitted when a directive that doesn't exist is used:

#clowns disable // OD0002, directive doesn't exist

0011 - BadExpression

This is emitted when an invalid expression is reached:

var/foo = initial(bar()) // OD0011, Expected field or index for initial(), got proc call result

0012 - MissingExpression

This is emitted when an embedded expression is expected in a string, but not found.

0019 - BadLabel

A code label could not be resolved by the compiler.

0050 - InvalidReference

A reference is being treated as a value.

var/meep = .. // OD0050, Attempt to use proc "..()" as value

0100 - BadArgument

Emitted when a known-invalid argument is being passed to a proc.

/proc/foo()
    return nameof(__TYPE__) // OD0100, Attempt to get nameof(__TYPE__) in global proc

0101 - InvalidArgumentKey

Emitted when an invalid expression is used as a key for an arguments list.

0102 - ArglistOnlyArgument

NOTE: Reserved for a currently-unimplemented emission.

0200 - HardReservedKeyword

NOTE: Currently unimplemented. This scenario currently emits "Expected end of object statement" errors. This code is emitted for keywords that are reserved and cannot be reasonably unreserved.

var/if = 7; // OD0200 - if is hard-reserved and cannot be the name of a variable

0404 - ItemDoesntExist

A generic error to imply that something is missing, such as a variable.

var/y = 5;
x = 3; // OD0404 - the variable x has yet to be defined

0405 - DanglingOverride

NOTE: Currently unimplemented. This fires when a proc's override is defined, but not the original proc.

/proc/foo() // original
/foo() // override
/poo() // OD0405 - no definition for /proc/poo() found

0406 - StaticOverride

This fires if you attempt to override a static, which is ill-formed in DM.

/foo
 var/static/x = 5
/foo/bar
 x = 6 // OD0406 - cannot override a static

0418 - IAmATeaPot

This is a reserved error for when OpenDream finally implements the HTCPC protocol.

0500 - HardConstContext

A non-constant is being used in a scenario that requires a constant.

var/const/foo = bar() // OD0500, Const var must be set to a constant

0501 - WriteToConstant

Emitted on an attempt to override a constant.

var/const/foo = 5
foo = 6 // OD0501, Cannot write to const var

0900 - InvalidInclusion

Emitted when anything other than a constant path is passed to #include

#include 1234 // OD0900, "1234" is not a valid include path

Preprocessor Configurable Errors (1000 - 1999)

Compiler Configurable Errors (2000 - 2999)

2000 - SoftReservedKeyword

For keywords that SHOULD be reserved, but don't have to be. 'null' and 'defined', for instance.

/proc/foo(null, defined, foobar) // OD2000 - null and defined are soft-reserved and shouldn't be used here. This is valid DM, though.
 return null; // Who knows what the heck this returns

2100 - DuplicateVariable

The same variable is defined several times.

var/x = 3;
var/x = 5; // OD2100 - x is already defined!

2200 - TooManyArguments

Too many arguments are passed to a native proc. Usually a compiletime or runtime in BYOND.

var/x = sin(5,3,2,1) // OD2200 - Too many args! Agh!

2205 - PointlessParentCall

A proc attempts to call a parent that does not exist, so the operation does nothing.

/proc/foo()
 . = ..() // OD2205 - Pointless call to parent

2206 - PointlessBuiltinCall

A call to a builtin proc doesn't actually do anything, or does something you may not expect it to.

/obj/var/static/x = 6
/proc/foo()
 var/obj/O = new
 O.x = 22
 var/x = initial(O.x) // OD2206 - Calling initial on a static returns its current value; x becomes 22 here.

2300 - MalformedRange

A range (such as within the case statement of a switch block) is malformed, featuring perhaps-unintended nulls, which will be coerced to 0.

/proc/foo()
 var/x = 0
 switch(x)
  if(null to 22) // OD2300 - Range is malformed, will end up being equivalent 0 to 22
   CRASH("I happen!");

2301 - InvalidRange

A range (such as within the case statement of a switch block) is invalid, as it features non-constant values, or strings. If not an error, strings and other non-numeric objects will be transmuted into zeroes. Most of these cases do actually compile in BYOND, so this is a non-fatal error.

/proc/huh()
 var/x = "c"
 switch(x)
  if("a" to "z") // OD2301 - this will become 0 to 0
   CRASH("No crash happens!")

2302 - InvalidSetStatement

A set statement has a definition which is invalid, likely because it is non-const. If not an error, the statement will be made equivalent to the last statement run. Since string interpolations like "A string with a [MACRO_CONSTANT]" are non-constant, this can result in unexpected behaviour:

#define WORD "hello"
/verb/hello
 set name = "hello there"
 set desc = "You use this verb to say [WORD]!" //OD2302 - The description will be set to "hello there"

2500 - MissingInterpolatedExpression

A text macro (\ref, \a, \him, etc) was missing a required interpolated expression.

var/message = "\a vendomat" //OD2500 - This will produce a slightly malformed string

2600 - AmbiguousResourcePath

Resource paths are case-insensitive, even when the filesystem is not. This emission means multiple files were found that could match the resource.

//OD2600 - Ambiguous resource path if both the files 'resource.txt' and 'RESOURCE.txt' exist
var/file = 'resource.txt'

Stylistic Configurable Errors (3000 - 3999)

3100 - EmptyBlock

Fires if a control-flow keyword is used without its corresponding block. Does not fire for empty functions.

/proc/test()
 if(TRUE) // OD3100 - Empty block detected
 else
  CRASH("The concept of truth has failed")
Clone this wiki locally