src/Messages.tbl
author David Anderson <dvander@alliedmods.net>
Sat Nov 17 18:41:01 2012 -0800 (2012-11-17)
changeset 195 c1ba166f3fc4
parent 194 b029d63565a2
child 212 443d24cfdf2d
permissions -rw-r--r--
Massive SemA/BC refactoring to support better type systems. Read on for more.

The previous compiler had a simple pipeline, best outlined as:
(1) Parsing and name binding -> AST
(2) Storage allocation -> AST
(3) Semantic Analysis (SemA) -> AST
(4) Bytecode Compilation (BC) -> Code

This pipeline, unfortunately, had two problems. First, name binding cannot be performed in one pass if we wish to have multi-file support in the form of modules. Name binding must be two-pass.

Second, because SemA was only capable of annotating AST nodes with a single type, most coercion work had to be duplicated in the BC phase, as coercion was not explicit in the SemA output. This made introducing new type rules extremely difficult, and all but precluded concepts like operator overloading (or overloading at all).

This patch rewrites most of Keima's backend. Of interest are the following changes:
(1) CompileContext has been refactored around future multi-file support.
(2) Parsing no longer performs any name binding.
(3) The grammar for type-and-name has been changed from:
(Label | Identifier)? Identifier
to:
Type? Identifier
where:
Type ::= OldType | NewType
OldType ::= Label
NewType ::= Identifier (. NewType)*


Although we do not implement the full production for Type yet, this
distinction is important. A type identifier is now affixed to the AST
as an Expression (right now, always a NameProxy), so it can fully
participate in name binding.

(4) Immediately after parsing, the AST goes through a NamePopulation phase.
This phase creates Scope objects for every scope which declares a name,
and if those names are declaring types or functions, a Symbol is created
and entered into the scope. Symbols entirely replace the old BoundName
classes.

(5) After NamePopulation comes NameBinding. This phase performs three steps:
(a) Links Scope objects together, to form a tree.
(b) Binds any free name to an existing name in the scope chain.
(c) Creates and registers any Symbols for names which have not yet been
added to the scope (for example, local variables).

In accordance, all "allocation" and "binding" concepts have been removed
from Scopes, which are now lightweight container classes.

(6) SemA now generates bytecode for each statement in the AST. Expression
compilation is performed via a separate mechanism called HIR (High-level
Intermediate Representation). To analyze an expression, SemA will walk
the AST, and produce a HIR object for each node. HIR is typed, and SemA
may insert coercion nodes, or even expand an AST node into multiple HIR
nodes. The result of evaluating an expression in SemA is therefore the
the root of a HIR tree, which SemA then sends to the HIRTranslator, which
performs bytecode generation.

As before, SemA still performs full semantic analysis. However, not it
also produces each function's bytecode.

This split allows us to decompose potentially complex semantics into
a more fine-grained, AST-like structure, which can have very simple
code-generation logic. For example, (1.0 + 5) might look like:

HAdd(HFloat(1.0), HConvert(HInteger(5), <Float>))

As part of this decomposition, many opcodes have been removed. Rather than
using typed jumps, we now expand jumps into longer tests. For example:
jge.f <label>
becomes:
ge.f
cvt.f2b
jt <label>

This simplifies the pipeline, and JITs should be able to melt the added
work away.

HIR is not used at a statement level, and HIR does not have any concept
of control-flow.

(7) The old BytecodeCompiler has been removed, as its work is now split
between SemA and HIRTranslator.


In addition, some minor refactorings have taken place:

(1) Opcodes.tbl no longer hardcodes numbers (aaah).
(2) Type has been split into smaller, typed structs.
(3) BytecodeEmitter no longer relies on Pools or RootScopes.
(4) SemA is now responsible for variable/storage allocation.
(5) Native table are now global, rather than per-module. As such, native
declarations now result in a Native object (which still requires a
CALLNATIVE opcode), which is an index into the global table. Natives
must be bound globally. This is in preparation for module support.
(6) Publics are no longer tracked, but rather registered via a global
callback upon module load. This callback can be set by embedders. This
is in preparation for multi-file support.
(7) The BytecodeEmitter now performs Symbol allocations itself, and it
also generates Code objects itself, which removes a good deal of
complexity.

Finally, a test harness has been added. This harness is a python script which finds *.test files, recursively, in the tests folder. For each file it runs the corresponding .sp. The contents of the .test file must match stdout+stderr.
dvander@25
     1
MSG(UnterminatedComment,            SyntaxError,            "unterminated comment")
dvander@25
     2
MSG(UnexpectedCharacter,            SyntaxError,            "unexpected character '%c' (code %02X)")
dvander@25
     3
MSG(UnterminatedString,             SyntaxError,            "unterminated string")
dvander@25
     4
MSG(UnknownEscapeCode,              SyntaxError,            "unknown escape code '%c'")
dvander@25
     5
MSG(ExpectedDigitForFloat,          SyntaxError,            "expected digit in float literal, got '%c'")
dvander@25
     6
MSG(WrongToken,                     SyntaxError,            "expected token '%s', got '%s'")
dvander@25
     7
MSG(ExpectedExpression,             SyntaxError,            "expected expression, got '%s'")
dvander@25
     8
MSG(RedeclaredName,                 SyntaxError,            "name '%s' was redeclared (previous at line %d, col %d)")
dvander@25
     9
MSG(ExpectedLValue,                 SyntaxError,            "impossible assignment, expected l-value")
dvander@25
    10
MSG(MaximumArrayDepth,              SyntaxError,            "maximum array dimension depth exceeded")
dvander@25
    11
MSG(ArrayInitializerDepth,          SyntaxError,            "array declaration and initializer have different dimension counts")
dvander@25
    12
MSG(BadArraySize,                   SyntaxError,            "array size must be positive")
dvander@25
    13
MSG(ArraySizeTooBig,                SyntaxError,            "array size is too big")
dvander@25
    14
MSG(EnumFieldNotConstant,           SyntaxError,            "enum fields must be constant integers")
dvander@25
    15
MSG(BreakOutsideLoop,               SyntaxError,            "break occurs outside any loop")
dvander@25
    16
MSG(ContinueOutsideLoop,            SyntaxError,            "continue occurs outside any loop")
dvander@25
    17
MSG(InvalidEnumName,                SyntaxError,            "invalid enumeration name")
dvander@25
    18
MSG(IndexMustBeInteger,             SyntaxError,            "array index must be integer")
dvander@25
    19
MSG(IndexBaseMustBeArray,           SyntaxError,            "cannot index into non-array")
dvander@25
    20
MSG(ArrayIsNotBoolean,              SyntaxError,            "cannot convert an array to boolean")
dvander@25
    21
MSG(CalleeNotFunction,              SyntaxError,            "callee is not a function")
dvander@25
    22
MSG(ArgumentCountMismatch,          SyntaxError,            "argument counts do not match")
dvander@25
    23
MSG(CannotAssignArrayToScalar,      SyntaxError,            "cannot coerce an array to a scalar")
dvander@25
    24
MSG(UnsupportedType,                SyntaxError,            "unsupported type")
dvander@25
    25
MSG(ArrayDimensionsMismatch,        SyntaxError,            "number of array dimensions does not match")
dvander@25
    26
MSG(ExpectedArray,                  SyntaxError,            "expected array")
dvander@25
    27
MSG(ArrayDimensionSizeMismatch,     SyntaxError,            "array dimension sizes do not match (level %d)")
dvander@25
    28
MSG(ArrayDimensionNotInteger,       SyntaxError,            "array dimension size must be an integer expression")
dvander@25
    29
MSG(ArrayNotSupported,              SyntaxError,            "array declaration not yet supported")
dvander@25
    30
MSG(ArrayInitializerUnknown,        SyntaxError,            "array initialized size is not known")
dvander@25
    31
MSG(DynamicArrayHasInitializer,     SyntaxError,            "dynamic arrays cannot have initializers")
dvander@25
    32
MSG(ArraySizeNotSpecified,          SyntaxError,            "array size was not specified")
dvander@25
    33
MSG(ArraySizeCannotBeDetermined,    SyntaxError,            "array size cannot be determined from initializer")
dvander@25
    34
MSG(ArrayAssignmentTooBig,          SyntaxError,            "destination array is too small")
dvander@25
    35
MSG(CannotDeclareStringCell,        SyntaxError,            "cannot declare a String cell")
dvander@25
    36
MSG(BinaryTypeError,                SyntaxError,            "operator '%s' does not support types '%s' and '%s'")
dvander@60
    37
MSG(UnaryTypeError,                 SyntaxError,            "operator '%s' does not support type '%s'")
dvander@60
    38
MSG(CantOpenFile,                   SyntaxError,            "cannot open file")
dvander@60
    39
MSG(ErrorSeekingFile,               SyntaxError,            "error seeking file")
dvander@60
    40
MSG(ErrorReadingFile,               SyntaxError,            "error reading file")
dvander@63
    41
MSG(ExpectedGlobal,                 SyntaxError,            "expected global variable or function")
dvander@63
    42
MSG(ForwardNotImplemented,          SyntaxError,            "forward '%s' not implemented")
dvander@66
    43
MSG(ForwardDeclareMismatches,       SyntaxError,            "declaration does not match original forward signature")
dvander@164
    44
MSG(ArrayCantBeReference,           SyntaxError,            "redundant reference qualifier on array parameter")
dvander@164
    45
MSG(StructCantBeReference,          SyntaxError,            "redundant reference qualifier on struct parameter")
dvander@67
    46
MSG(ArraySizeMustBeConstant,        SyntaxError,            "array size must be a constant integer")
dvander@68
    47
MSG(ReferenceIsConstant,            SyntaxError,            "cannot assign to a constant lvalue")
dvander@68
    48
MSG(MultiArrayInNative,             SyntaxError,            "multidimensional arrays cannot be passed to natives")
dvander@68
    49
MSG(InvalidVarArgs,                 SyntaxError,            "varargs cannot be const or ref")
dvander@68
    50
MSG(VarArgsOutsideNative,           SyntaxError,            "variadic arguments can only be specified on natives")
dvander@69
    51
MSG(ArrayTooBig,                    TypeError,              "array size is too large")
dvander@69
    52
MSG(IntegerDivideByZero,            TypeError,              "integer divide by zero")
dvander@69
    53
MSG(ArrayIndexOutOfBounds,          TypeError,              "array index %d is out of bounds [0, %d)")
dvander@69
    54
MSG(NativeNotBound,                 TypeError,              "attempted to call unbound native \"%s\"")
dvander@69
    55
MSG(AllocationOverflow,             SystemError,            "allocation request overflowed")
dvander@71
    56
MSG(TooMuchRecursion,               SystemError,            "stack overflow: too much recursion")
dvander@71
    57
MSG(MissingReturnValue,             SyntaxError,            "tagged function must return a value")
dvander@71
    58
MSG(NotAllPathsReturnValue,         SyntaxError,            "not all paths through function return a value")
dvander@71
    59
MSG(UsedVoidReturn,                 SyntaxError,            "return value expected, but function does not return a value")
dvander@84
    60
MSG(FunctionDoesNotReturnValue,     SyntaxError,            "cannot use the result of a function with no return value")
dvander@129
    61
MSG(IdentifierNotFound,             SyntaxError,            "identifier '%s' could not be found")
dvander@148
    62
MSG(TypeMismatchDuringInvoke,       TypeError,              "incoming type '%s' does not match signature type '%s'")
dvander@129
    63
MSG(CannotInvokeReturnType,         SyntaxError,            "cannot invoke function with return type '%s'")
dvander@145
    64
MSG(IdentifierIsNotAType,           SyntaxError,            "identifier '%s' cannot be used as a type")
dvander@148
    65
MSG(TypeMismatch,                   TypeError,              "type mismatch (expected '%s', got '%s')")
dvander@148
    66
MSG(PropertyNotFound,               TypeError,              "property '%s' not found on type '%s'")
dvander@168
    67
MSG(MustBeConstant,                 SyntaxError,            "default value must be a constant")
dvander@172
    68
MSG(DefaultMustBeLastCase,          SyntaxError,            "the \"default\" case must be the last case in a switch statement")
dvander@172
    69
MSG(OneDefaultPerSwitch,            SyntaxError,            "only one default case is allowed per switch")
dvander@172
    70
MSG(SingleStatementPerCase,         SyntaxError,            "only one statement is allowed per case")
dvander@172
    71
MSG(CaseMustBeConstant,             SyntaxError,            "case expression must be a constant")
dvander@172
    72
MSG(CaseHasSameValue,               SyntaxError,            "case value appears twice in the same switch")
dvander@172
    73
MSG(CaseMustBeInteger,              SyntaxError,            "switch may only operate on integer values")
mibusby@180
    74
MSG(StructCantBeEmpty,              SyntaxError,            "struct cannot be declared without any fields")
dvander@187
    75
MSG(CannotInitializeEvalArray,      SyntaxError,            "cannot mix dynamic array sizes and initializers")
dvander@187
    76
MSG(ExpectedStringLiteral,          SyntaxError,            "expected string literal")
dvander@187
    77
MSG(UnexpectedArrayLiteral,         SyntaxError,            "unexpected array literal")
dvander@187
    78
MSG(InvalidDimensionSize,           TypeError,              "invalid size %d for dimension %d")
dvander@188
    79
MSG(CannotComputeIndexRef,          SyntaxError,            "cannot use an array index as a reference")
dvander@190
    80
MSG(BadDynamicInitializer,          SyntaxError,            "dynamic length specified, but preceding array is empty")
dvander@194
    81
MSG(SizeofNeedsArray,               TypeError,              "sizeof requires an array")
dvander@195
    82
MSG(ImportsMustBeFirst,             SyntaxError,            "import statements must come before other statements")
dvander@195
    83
MSG(ImportedNameAlreadyBound,       TypeError,              "imported name has already been bound")
dvander@195
    84
MSG(CannotResolveImport,            TypeError,              "cannot resolve import %s")