Skip to content

Commit

Permalink
LLVM2: Compiling array literals
Browse files Browse the repository at this point in the history
Add support for instance and static method generation, to generate code
for constructing arrays. This uses the native implementation of
Array.withCapacity (which in turn leverages the built-in Pointer<T>
type). At this point, only the code which is actually reachable is
generated, so dead code removal is the default (I'm not sure if I'll
be able to keep that up, but for now it's pretty cool).
  • Loading branch information
kengorab committed Oct 20, 2023
1 parent b1b493e commit c02bbf3
Show file tree
Hide file tree
Showing 4 changed files with 541 additions and 103 deletions.
42 changes: 33 additions & 9 deletions abra_cli/abra-files/example.abra
Original file line number Diff line number Diff line change
@@ -1,11 +1,35 @@
//val null = Pointer.null<Int>()
//null.address()
//null.load()
//val arr1 = Array.withCapacity<String>(6)
//val arr2 = Array.withCapacity<Bool>(6)
//val arr3 = Array.withCapacity<Bool[]>(6)

//val ptr = Pointer.malloc<Int>()
//ptr.address()
//arr1.push("a")
//arr1.push("b")
//arr1.push("c")
//arr1.push("d")
//arr1.push("e")
//arr1.get(4)

val arr1 = [1, 2, 3]
//val arr2 = ["a", "b", "c"]
//val arr3 = [true, false]
//
//0

val p = Pointer.malloc<Int>(1)
p.address()

// // A value of an optional (nullable) type must be a 64-bit value. The value of None is 0x8000000000000000.
// // If underlying type is a pointer (object), use pointer tag to denote None-ness by setting lowest bit to 1
// val s: String = "abc" // 0x0000600001AD4040 (ordinary String value)
// val s: String? = "abc" // 0x0000600001AD4040 <--- highest bit is set to 0
// val s: String? = None // 0x8000000000000000 <--- highest bit is set to 1 to denote `None`
//
// // If type is a primitive then we need to do some things differently.
// // If value is Int (32-bit):
// val i: Int = 123 // 0x0000007B (ordinary Int (32-bit) value)
// val i: Int? = 123 // 0x000000000000007B <--- 32-bit value extended to 64-bits, highest bit 0
// val i: Int? = None // 0x8000000000000000 <--- 32-bit value extended to 64-bits, highest bit 1
//
// // If value is Float, we can use NaN boxing to encode a None value (alongside NaN, and +-Inf)
// // If value is Bool (1-bit), we behave like Int - extend to 64 bits, set top bit to 1 if None

val ptr = Pointer.malloc<String>(2)
ptr.store("abc")
ptr.offset(1).store("def")
ptr.offset(1).load()
30 changes: 21 additions & 9 deletions abra_core/src/typechecker/prelude.stub.abra
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,31 @@ type Pointer<T> {
}

type Array<T> {
length: Int readonly
length: Int

_buffer: Pointer<T> = Pointer.null<T>()
_capacity: Int = 0

// _buffer: Pointer<T> = Pointer.null()
// _capacity: Int = 0
//
// func withCapacity<U>(initialCapacity: Int): U[] {
// //val buffer = Pointer.malloc(initialCapacity)
// Array<U>(length: 0, _buffer: Pointer.malloc(initialCapacity), _capacity: initialCapacity)
// }
func withCapacity<T>(initialCapacity: Int): T[] {
Array<T>(
length: 0,
_buffer: Pointer.malloc<T>(initialCapacity),
_capacity: initialCapacity
)
}

@Stub func isEmpty(self): Bool
@Stub func enumerate(self): (T, Int)[]
@Stub func push(self, item: T, *others: T[])

func push(self, item: T) {
self._buffer.offset(self.length).store(item)
self.length += 1
}

func get(self, index: Int): T {
self._buffer.offset(index).load()
}

@Stub func pop(self): T?
@Stub func popFront(self): T?
@Stub func splitAt(self, index: Int): (T[], T[])
Expand Down
3 changes: 2 additions & 1 deletion abra_core/src/typechecker/typechecker2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,7 @@ impl Type {
Type::Primitive(PrimitiveType::Bool) => Some(project.prelude_bool_struct_id),
Type::Primitive(PrimitiveType::String) => Some(project.prelude_string_struct_id),
Type::GenericInstance(struct_id, _) => Some(*struct_id),
Type::Type(TypeKind::Struct(struct_id)) => Some(*struct_id),
_ => None
}
}
Expand Down Expand Up @@ -885,7 +886,7 @@ pub enum TypedNode {
Map { token: Token, items: Vec<(TypedNode, TypedNode)>, type_id: TypeId },
Identifier { token: Token, var_id: VarId, type_arg_ids: Vec<(TypeId, Range)>, type_id: TypeId },
NoneValue { token: Token, type_id: TypeId },
Invocation { target: Box<TypedNode>, arguments: Vec<Option<TypedNode>>, type_id: TypeId },
Invocation { target: Box<TypedNode>, arguments: Vec<Option<TypedNode>>, type_id: TypeId }, // TODO: ::Invocation should have type_arg_ids: Vec<(TypeId, /* inferred: */ bool)>
Accessor { target: Box<TypedNode>, kind: AccessorKind, is_opt_safe: bool, member_idx: usize, member_span: Range, type_id: TypeId, type_arg_ids: Vec<(TypeId, Range)> },
Indexing { target: Box<TypedNode>, index: IndexingMode<TypedNode>, type_id: TypeId },
Lambda { span: Range, func_id: FuncId, type_id: TypeId },
Expand Down
Loading

0 comments on commit c02bbf3

Please sign in to comment.