aboutsummaryrefslogtreecommitdiff
path: root/hobgoblin/src
diff options
context:
space:
mode:
Diffstat (limited to 'hobgoblin/src')
-rw-r--r--hobgoblin/src/patio.hob84
-rw-r--r--hobgoblin/src/patio/instructions.hob253
-rw-r--r--hobgoblin/src/patio/operands.hob39
-rw-r--r--hobgoblin/src/patio/types.hob123
-rw-r--r--hobgoblin/src/patio/values.hob43
5 files changed, 542 insertions, 0 deletions
diff --git a/hobgoblin/src/patio.hob b/hobgoblin/src/patio.hob
index e69de29b..5a2d0734 100644
--- a/hobgoblin/src/patio.hob
+++ b/hobgoblin/src/patio.hob
@@ -0,0 +1,84 @@
+import {Source} from ./sources;
+import {PatioInstruction} from ./patio/instructions;
+import {PatioDataLayout, PatioDataValue, PatioType} from ./patio/types;
+
+// == Compilation units ==
+
+struct PatioCompilationUnit {
+ field elements: List[PatioCompilationUnitElement];
+ field source: Source;
+}
+
+// == Compilation unit elements ==
+
+sum PatioCompilationUnitElement {
+ variant PatioDataElementImmutableDefinition;
+ variant PatioDataElementMutableDeclaration;
+ variant PatioDataElementMutableDefinition;
+ variant PatioExceptionTypeDefinition;
+ variant PatioFunctionDeclaration;
+ variant PatioFunctionDefinition;
+}
+
+struct PatioDataElementImmutableDefinition {
+ field name: String;
+ field visibility: PatioVisibility;
+ field value: PatioDataValue;
+ field source: Source;
+}
+
+struct PatioDataElementMutableDeclaration {
+ field name: String;
+ field layout: PatioDataLayout;
+ field source: Source;
+}
+
+struct PatioDataElementMutableDefinition {
+ field name: String;
+ field visibility: PatioVisibility;
+ field initialValue: PatioDataValue;
+ field source: Source;
+}
+
+struct PatioExceptionTypeDefinition {
+ field name: String;
+ field valueType: PatioType;
+ field source: Source;
+}
+
+struct PatioFunctionDeclaration {
+ field name: String;
+ field params: List[PatioLocal];
+ field returnTypes: List[PatioType];
+ field source: Source;
+}
+
+struct PatioFunctionDefinition {
+ field name: String;
+ field visibility: PatioVisibility;
+ field locals: List[PatioLocal];
+ field returnTypes: List[PatioType];
+ field body: List[PatioInstruction];
+ field source: Source;
+}
+
+// == Visibility ==
+
+enum PatioVisibility {
+ variant private;
+ variant public;
+}
+
+// == Locals ==
+
+struct PatioLocal {
+ field name: String;
+ field type: PatioType;
+ field localType: PatioLocalType;
+}
+
+enum PatioLocalType {
+ variant param;
+ variant val;
+ variant var;
+}
diff --git a/hobgoblin/src/patio/instructions.hob b/hobgoblin/src/patio/instructions.hob
new file mode 100644
index 00000000..c6f33976
--- /dev/null
+++ b/hobgoblin/src/patio/instructions.hob
@@ -0,0 +1,253 @@
+import {Source} from ../sources;
+import {PatioLocalRef, PatioOperand} from ./operands;
+import {PatioDataLayout} from ./types;
+
+sum PatioInstruction {
+ variant PatioBlock;
+ variant PatioBoolToInt;
+ variant PatioCall;
+ variant PatioCallPointer;
+ variant PatioDataPtrToInt;
+ variant PatioIf;
+ variant PatioIntAdd;
+ variant PatioIntEquals;
+ variant PatioIntNotEqual;
+ variant PatioIntSub;
+ variant PatioIntToBool;
+ variant PatioIntToDataPtr;
+ variant PatioLocalStore;
+ variant PatioLoop;
+ variant PatioLoopBreak;
+ variant PatioLoopContinue;
+ variant PatioMemoryLoad;
+ variant PatioMemoryStore;
+ variant PatioReturn;
+ variant PatioSwitch;
+ variant PatioThrow;
+ variant PatioTry;
+ variant PatioUnreachable;
+ variant PatioVarLoad;
+ variant PatioVarStore;
+}
+
+/// Execute the instructions in the body of the block. The results may be used in
+/// the parent scope, but any other variables (as distinct from values) are no
+/// longer in use.
+struct PatioBlock {
+ field body: List[PatioInstruction];
+ field results: List[PatioOperand];
+ field source: Source;
+}
+
+struct PatioBoolToInt {
+ field destination: PatioLocalRef;
+ field value: PatioOperand;
+ field source: Source;
+}
+
+/// Call the function with the given name, and store the returned values in the
+/// destination locals.
+struct PatioCall {
+ field destinations: List[PatioLocalRef];
+ field functionName: String;
+ field args: List[PatioOperand];
+ field source: Source;
+}
+
+/// Call the function pointed to by the function pointer with the given
+/// arguments, and store the returned values in the destination locals.
+struct PatioCallPointer {
+ field destinations: List[PatioLocalRef];
+ field functionPointer: PatioOperand;
+ field args: List[PatioOperand];
+ field source: Source;
+}
+
+struct PatioDataPtrToInt {
+ field destination: PatioLocalRef;
+ field value: PatioOperand;
+ field source: Source;
+}
+
+/// If the condition is true, execute the instructions in the "true" body,
+/// otherwise execute the instructions in the "false" body.
+///
+/// Each block must have the same number of results as destinations. Each result is
+/// assigned to the destination with the same index.
+struct PatioIf {
+ field destinations: List[PatioLocalRef];
+ field condition: PatioOperand;
+ field trueBody: PatioBlock;
+ field falseBody: PatioBlock;
+ field source: Source;
+}
+
+struct PatioIntAdd {
+ field destination: PatioLocalRef;
+ field left: PatioOperand;
+ field right: PatioOperand;
+ field source: Source;
+}
+
+struct PatioIntEquals {
+ field destination: PatioLocalRef;
+ field left: PatioOperand;
+ field right: PatioOperand;
+ field source: Source;
+}
+
+/// Compare the left and right operands. If they are equal, store false in the
+/// destination, otherwise store true in the destination.
+struct PatioIntNotEqual {
+ field destination: PatioLocalRef;
+ field left: PatioOperand;
+ field right: PatioOperand;
+ field source: Source;
+}
+
+/// Calculate the left operand minus the right operand, and store the result in
+/// the destination.
+struct PatioIntSub {
+ field destination: PatioLocalRef;
+ field left: PatioOperand;
+ field right: PatioOperand;
+ field source: Source;
+}
+
+struct PatioIntToBool {
+ field destination: PatioLocalRef;
+ field value: PatioOperand;
+ field source: Source;
+}
+
+struct PatioIntToDataPtr {
+ field destination: PatioLocalRef;
+ field value: PatioOperand;
+ field source: Source;
+}
+
+/// Store the given value in the destination local.
+struct PatioLocalStore {
+ field destination: PatioLocalRef;
+ field value: PatioOperand;
+ field source: Source;
+}
+
+/// Execute the body. The `continue` instruction can jump back to the
+/// start of the body. The `break` instruction can jump to the end of
+/// the body.
+struct PatioLoop {
+ field body: List[PatioInstruction];
+ field source: Source;
+}
+
+/// Jump to the end of the enclosing `loop` instruction's body.
+struct PatioLoopBreak {
+ field source: Source;
+}
+
+/// Jump to the start of the enclosing `loop` instruction's body.
+struct PatioLoopContinue {
+ field source: Source;
+}
+
+/// Load the value at the given offset from the given pointer and store it in the
+/// destination local.
+struct PatioMemoryLoad {
+ field destination: PatioLocalRef;
+ field pointer: PatioOperand;
+ field layout: PatioDataLayout;
+ field elementOffsets: List[Int32];
+ field source: Source;
+}
+
+/// Store the given value at the given offset from the given pointer.
+struct PatioMemoryStore {
+ field pointer: PatioOperand;
+ field layout: PatioDataLayout;
+ field elementOffsets: List[Int32];
+ field value: PatioOperand;
+ field source: Source;
+}
+
+/// Return with the given values from the current function.
+struct PatioReturn {
+ field values: List[PatioOperand];
+ field source: Source;
+}
+
+/// Find a case with a value matching that of the instruction's value. If such a
+/// case is found, execute the body of that case, otherwise execute the default
+/// body.
+///
+/// Each block must have the same number of results as destinations. Each result
+/// is assigned to the destination with the same index.
+struct PatioSwitch {
+ field destinations: List[PatioLocalRef];
+ field value: PatioOperand;
+ field cases: List[PatioSwitchCase];
+ field defaultBody: PatioBlock;
+ field source: Source;
+}
+
+struct PatioSwitchCase {
+ field value: Int32;
+ field body: PatioBlock;
+ field source: Source;
+}
+
+/// Search the stack for an exception handler with a catch clause matching the
+/// thrown exception type. Unwind the stack up to and including this exception
+/// handler, and run the body of the catch clause. If no such exception handler
+/// is found, the process should abort.
+struct PatioThrow {
+ field exceptionTypeName: String;
+ field value: PatioOperand;
+ field source: Source;
+}
+
+/// Push an exception handler with the given catch clauses onto the control flow
+/// stack, and then execute the instructions in its body.
+///
+/// If the exception handler catches an exception, the body of the corresponding
+/// is executed instead.
+///
+/// Each block (that is, the body of the try and the body of each catch clause)
+/// must have the same number of results as destinations. Each result is assigned to
+/// the destination with the same index.
+struct PatioTry {
+ field destinations: List[PatioLocalRef];
+ field catchClauses: List[PatioCatchClause];
+ field body: PatioBlock;
+ field source: Source;
+}
+
+/// A catch clause can accept an exception of a given type. If executed, it will
+/// stored the value of the exception in the given destination, and then execute the
+/// body.
+struct PatioCatchClause {
+ field exceptionTypeName: String;
+ field destination: PatioLocalRef;
+ field body: PatioBlock;
+ field source: Source;
+}
+
+/// Unreachable instructions have undefined behaviour, and are used to indicate
+/// that an instruction sequence is unreachable.
+struct PatioUnreachable {
+ field source: Source;
+}
+
+/// Load the value from the given var and store it in the destination local.
+struct PatioVarLoad {
+ field destination: PatioLocalRef;
+ field var: PatioLocalRef;
+ field source: Source;
+}
+
+/// Store the given value in the destination var.
+struct PatioVarStore {
+ field var: PatioLocalRef;
+ field value: PatioOperand;
+ field source: Source;
+}
diff --git a/hobgoblin/src/patio/operands.hob b/hobgoblin/src/patio/operands.hob
new file mode 100644
index 00000000..5a8769f7
--- /dev/null
+++ b/hobgoblin/src/patio/operands.hob
@@ -0,0 +1,39 @@
+import {PatioDataPtrValue, PatioIntValue} from ./values;
+
+sum PatioOperand {
+ variant PatioLocalRef;
+ variant PatioBoolConst;
+ variant PatioByteConst;
+ variant PatioDataPtrConst;
+ variant PatioFunctionPtrConst;
+ variant PatioInt32Const;
+ variant PatioIntConst;
+}
+
+struct PatioLocalRef {
+ field name: String;
+}
+
+struct PatioBoolConst {
+ field value: Bool;
+}
+
+struct PatioByteConst {
+ field value: Int8;
+}
+
+struct PatioDataPtrConst {
+ field value: PatioDataPtrValue;
+}
+
+struct PatioFunctionPtrConst {
+ field name: String;
+}
+
+struct PatioInt32Const {
+ field value: PatioIntValue;
+}
+
+struct PatioIntConst {
+ field value: PatioIntValue;
+}
diff --git a/hobgoblin/src/patio/types.hob b/hobgoblin/src/patio/types.hob
new file mode 100644
index 00000000..3155e576
--- /dev/null
+++ b/hobgoblin/src/patio/types.hob
@@ -0,0 +1,123 @@
+import {PatioDataPtrValue, PatioIntValue} from ./values;
+
+// == Types ==
+
+sum PatioType {
+ variant PatioBoolType;
+ variant PatioByteType;
+ variant PatioDataPtrType;
+ variant PatioFunctionPtrType;
+ variant PatioInt32Type;
+ variant PatioIntType;
+}
+
+struct PatioBoolType {
+ singleton;
+}
+
+struct PatioByteType {
+ singleton;
+}
+
+struct PatioDataPtrType {
+ singleton;
+}
+
+struct PatioFunctionPtrType {
+ singleton;
+}
+
+struct PatioInt32Type {
+ singleton;
+}
+
+struct PatioIntType {
+ singleton;
+}
+
+// == Data layouts ==
+
+sum PatioDataLayout {
+ variant PatioDataLayoutArray;
+ variant PatioDataLayoutBool;
+ variant PatioDataLayoutByte;
+ variant PatioDataLayoutDataPtr;
+ variant PatioDataLayoutFunctionPtr;
+ variant PatioDataLayoutInt;
+ variant PatioDataLayoutInt32;
+ variant PatioDataLayoutStruct;
+}
+
+struct PatioDataLayoutArray {
+ field element: PatioDataLayout;
+ field size: Int32;
+}
+
+struct PatioDataLayoutBool {
+ singleton;
+}
+
+struct PatioDataLayoutByte {
+ singleton;
+}
+
+struct PatioDataLayoutDataPtr {
+ singleton;
+}
+
+struct PatioDataLayoutFunctionPtr {
+ singleton;
+}
+
+struct PatioDataLayoutInt {
+ singleton;
+}
+
+struct PatioDataLayoutInt32 {
+ singleton;
+}
+
+struct PatioDataLayoutStruct {
+ field elements: List[PatioDataLayout];
+}
+
+// == Data values ==
+
+sum PatioDataValue {
+ variant PatioDataValueArray;
+ variant PatioDataValueBool;
+ variant PatioDataValueByte;
+ variant PatioDataValueDataPtr;
+ variant PatioDataValueInt;
+ variant PatioDataValueInt32;
+ variant PatioDataValueStruct;
+}
+
+struct PatioDataValueArray {
+ field elementLayout: PatioDataLayout;
+ field elements: List[PatioDataValue];
+}
+
+struct PatioDataValueBool {
+ field value: Bool;
+}
+
+struct PatioDataValueByte {
+ field value: Int8;
+}
+
+struct PatioDataValueDataPtr {
+ field value: PatioDataPtrValue;
+}
+
+struct PatioDataValueInt {
+ field value: PatioIntValue;
+}
+
+struct PatioDataValueInt32 {
+ field value: PatioIntValue;
+}
+
+struct PatioDataValueStruct {
+ field elements: List[PatioDataValue];
+}
diff --git a/hobgoblin/src/patio/values.hob b/hobgoblin/src/patio/values.hob
new file mode 100644
index 00000000..0e14cf35
--- /dev/null
+++ b/hobgoblin/src/patio/values.hob
@@ -0,0 +1,43 @@
+import {PatioDataLayout} from ./types;
+
+// == Data ptr values ==
+
+sum PatioDataPtrValue {
+ variant PatioDataPtrValueDataElement;
+ variant PatioDataPtrValueNull;
+}
+
+struct PatioDataPtrValueDataElement {
+ field name: String;
+}
+
+struct PatioDataPtrValueNull {
+}
+
+// == Int values ==
+
+/// An int value that is a constant in the compiled program, but may differ
+/// across targets.
+sum PatioIntValue {
+ variant PatioIntValueByteOffsetOf;
+ variant PatioIntValueByteSizeOf;
+ variant PatioIntValueLiteral;
+}
+
+/// The offset, in bytes, of an offset in a data layout.
+struct PatioIntValueByteOffsetOf {
+ field layout: PatioDataLayout;
+ field elementOffsets: List[Int32];
+}
+
+/// The size, in bytes, of a data layout.
+struct PatioIntValueByteSizeOf {
+ field layout: PatioDataLayout;
+}
+
+/// An int value that is the same across all targets.
+struct PatioIntValueLiteral {
+ field value: Int32;
+}
+
+