Skip to content

Latest commit

 

History

History
708 lines (634 loc) · 32 KB

File metadata and controls

708 lines (634 loc) · 32 KB

"C with typeclasses and tagged unions"

GOOD IDEAS 11/13

  • When converting a lambda to a dyn lambda, put its environments in the current allocator instead of on the stack
  • language level hot reload support. TWEAK_FLOAT(f) thing. Explore this and find out if language support really helps or if it can just be solved by library
  • Specialization solution (when types are known by the function)
  • A kind of *pattern* that checks the type and binds a variable of that type! What other thing for a feature that needs to _check_ and _bind_ than a pattern?!
    

More optimal final programs

  • Represent payload-less either types as ints not structs (Actually might just add enum as separate thing from eithers)
  • Add 'switch' to bytecode; compile switches with no patterns or guards to LLVM switch
  • Unit syntax of '()', as well as the name unit by the way, makes no sense when we don't have tuples. What about {}

Non-major Ideas

  • c"" string literals that are of type ptr (what about interpolation?)
  • userland: CCompatString which is a valid c string with length in front of the allocation (ill call it antirez strings)
  • User-defined implicit conversions: based on a special ability that integrates with type inference? (like Mojo's ImplicitlyIntable, etc): ImplicitAs?
  • [design/flags_in_tags.k1]
  • Dogfood idea: 'niched' integer abstraction (-1 as 'not found' but safely, vs using option and wasting space + adding more code) impl Unwrap<Inner = u32> for { hidden: i64 }
  • Incorporate ffc.h for int and float parsing
  • Inspired by fast_float, char to digit lookup table

Syntax/elegance

  • replace \ with 'fn' for lambda notation, one more character and we can be similarly elegant, \x.x becomes fn x.x
  • The dereference operator does the opposite of what it looks like: it unpointers things, where the star in the rest of the language makes pointers or keeps them
  • Destructuring, (in)fallible patterns
  • Default type args for abilities, or partially applied abilities (alias Unwrap[T] = Try[T, unit])
  • Rename view to span
  • Rename 'static' types to 'static value' types
  • Need a way to write an interpolated string to a Writer that you already have Let's just call it 'fmt' and make it a special construct
  • syntax sugar for the continuous collection types: array, view, buffer. something like [N] T, [] T, [rw] T
    • Actually, I think this is bad. Came up with [] T, [mut] T, [+] T, and [N] T, but the names are better
  • Lowercase most types, they look overly important, and move to kebab-case to avoid uppercase awkwardness
    • Allow users to capitalize domain types, but types like List/Opt/Buffer/Result should sink into the background
  • Replace the builtin for ... yield with a userspace function taking a lambda
  • Eschew the name 'Unwrap'; twitter is right about that one. Good opportunity to produce a very strong name for this concept
  • Consider a rename of 'uword/iword'; they do not feel good to use. What about u and i.
    • Ok now I'm really thinking about size and it being signed.
    • Also: do safe integer coercions automatically
  • Allow omission of empty paren pair when type args are passed, getTypeName[T] vs getTypeNameT

Simple but missing

  • decide if overflow traps or not (in debug and release, if those are even different)
  • good backtraces (https://claude.ai/share/245cf54a-22cc-4fb1-8f17-3fd6b2c42812)
  • support ability constraints on generics
  • support explicit type args in AnonEnumConstructor syntax
  • Allow scoped namespace defns; namespace <ident>/<ident>/<ident> {}, great for metaprogramming to inject stuff currently you could easily just ns <ident> { ns <ident> { ns <ident> _stuff_ } } }
  • META test: Can we build ArrayOfStructs using current metaprogramming?!
  • Bindings generator; rust-bindgen equivalent
  • implement iterator for array

Bugs

  • Defect: Allow pattern matching into recursive types (currently we just terminate)
  • Defect: Generic (co)recursive types do not work
  • Require that a blanket impl's params appear in the Self type
  • [-] Limitation (ordering): ability impls have to be provided in dependency order, since their constraints can depend on each other. I think I have to do a 'skip and progress' style of pass for them to prevent that. It possibly not worth the complexity

[ ] Writergate

  • Allow using expr-interpolated strings directly into a writer

  • Allow for named non-interpolated args into holes with a struct

  • Implement at least one format specifier (precision, pretty)

  • Return value binding, or named return values, for guaranteed RVO

  • Uninit in struct fields - just don't store there

[ ] Context ability types

  • AbilitySignature as context variable kind in addition to Type (enables context Writer, context Mem if it ends up an ability)
    • let context(impl Alloc) temp = mem/AllocMode.Arena;
    • let context(impl Iterator[string]) temp = mem/AllocMode.Arena;

[ ] Distribute builds that work

  • Test on linux
  • Link in lld? ugh. For now maybe just ship with it
  • [ ]

Project: Optimize the bytecode a bit

  • Function inlining
  • Prune unreachable blocks

Project: di. Debug Info tidyups

  • Fix random jumping to function header
  • Annotate U8s with boolean somehow where they are actually booleans

Project: Recursive types take 2

  • Remove RecursiveReference; make visitors detect cycles
  • add test with co-recursion and infinite recursion
  • Support deeper pattern matching on recursive types

VM Profiler: Instrument the vm itself

K1 Profiler

Add core and/or compiler support to allow block profiling of k1 programs

Project: Redesign the physical representation of enums

  • Implement union as a thing
  • Represent enums as { tag, union }, not union { tag, payload }, { tag, payload }, ...
  • Classify like structs for ABI handling; test with mirrored C types
  • Rename Enum -> Sum or DUnion in the code
  • Optimize no-payload enums into non-aggregates, at the typer level.

Project: Instruction-level IR ('bytecode')

Primarily an execution target for the VM, but also would DRY up the significant duplication between the two current backends, LLVM and k1::vm.

  • Try to compile a function to bytecode
  • Draw the rest of the owl (done)

Project: Optimize StaticValue representation for aggregates to be the same as the VM representation

  • [-] Real layouts, in a mem pool, to save roundtripping and increase locality -> Kinda done, we now re-use the values in a global 'static stack'
  • We'll want to skip the id-based repr entirely for heavy heavy static data I think

Project: Arena-based core, builtins, stdlib

  • Thread-local globals
  • bitcast function (for struct ABI workarounds right now)

Project: Ability objects; dyn[]

Project: Static Improvements

  • Collapse long runs of zero-only data into a single one in LLVM IR (e.g., mem/allocStack)
  • static #for, special-case like IF. Can unroll the loop at comptime but the body is runtime
  • VM "PermSpace" for caching converted static values in their VM representation
  • Add StaticValue::Zero as an efficient special-case (generalization of the existing NullPointer, actually)
  • 'Type predicate': functions taking only a single type could be invoked with a nice syntax like type.sizeOf
  • 'Type predicate' functions as type bounds

Introduce Warnings

  • Unused var
  • Unused type bound
  • Footgun, warn on naked variable patterns in 'is'
    • if self.slots.get(probe_index) is None {

Project: Zero-Sized Types

  • Treat Unit and empty Struct as ZSTs
  • Compile ZSTs to missing arguments, and LLVM void returns, and no-ops inside other types
  • Treat statics as ZSTs
  • Think about never in either variants: Is it a ZST? Does it make the variant unreachable? Result[T, never]

Project: system interface, 'Write' ability and intrinsic fix.

Project: More LSP features

  • Hover first pass
  • Hover much better
  • Hover no more markdown
  • Go-to
  • Completion

Project: Actual modules, library vs binary compile, allow linker options

  • Separate modules
    • Introduce 'module' w/ kind (lib/bin/core), deps, and namespace+scope
    • Add entire modules from TypedProgram
    • Module manifests somewhere
    • Library vs Binary
    • Prevent modules using definitions from modules they dont depend on (implicit transitive dependency problem)
    • Dependencies: local module
    • Specify linked libraries in manifest (Eventually this will need to be more customizable)
    • serialize typedprogram at each module completion (for incremental compilation)
  • clang passthrough options, when do we 'link', in IR or as object files, ...
    • we 'link' with k1 in the typer's modules system
    • we link with other deps w/ the linker

Project: Make llvm codegen run off our bytecode

It currently runs directly off the typed tree

  • Rewrite llvm type generation in terms of PhysicalType
  • Rewrite Dwarf type generation in terms of PhysicalType
  • Implement every instruction
  • Augment bytecode function metadata and signatures

Project: struct passing ABI for aarch64 and x86_64

  • Add abi mapping step to function type generation
  • Classify eightbytes for x86
  • Add marshal/re-canonicalize steps in caller/callee code
  • Commit a test in test suite

Profiler dogfood round

  • Introduce an "uninitialized" specifier, similar to zeroed()
  • Add 'zeroed()' static value special case for efficiency?
  • provide a way to specify if globals are comptime available or just runtime globals? I accidentally wrapped a global defn in #static...

Project: VM for static execution

  • vm: static execution
    • Order-independence for globals used in static code
    • Static Buffers (slices)
      • vm -> static
      • static -> vm
      • LLVM gen
    • reference to reference cast
    • Introduce uword/iword types
    • Switch to a single stack
    • Move to intrinsic: system core memory functions
    • Move to intrinsic: memcpy/memmove
    • Allow 'write's from static code
    • Move to intrinsic: exit
    • Run global initializers before most bodies but after all other phases, treat it like 'body' code SINCE it'll end up using the user's types, and even impls!
    • Define clear 'platform layer' (crash, assert, mem, other?). Then we could do an LLVM interp platform and a rust interpreter platform
    • All tests passing in #static mode
    • Allow upgrading static buffers to fixed-length Arrays (so cool actually)

Project: Mutable and non-mutable reference types

  • Change pointer syntax: *<ty>, *<ty>, *mut <ty>
  • Rename 'Buffer' to ... View?
  • Convert reference type syntax to prefix for better chaining
  • Convert option to prefix syntax
  • Add mutable/const bool to ReferenceType
  • Update stdlib

Project: Metaprogramming system built on 'static': both string #insert and parsed code #insert, like Jai

  • #meta First working version
  • Multiline string literals,
  • #code directive
  • static type universe: static T
  • A syntax for talking about a certain impl of an ability: Show::bool/show(b: bool) or (Allocator for T)/supportsFree()

Project: Metaprogramming round 2

  • Finish StructOfArrays builder
  • Provide in-file 'meta' module for convenience (it gets pre-compiled as its own module so that you can write and use functions for metaprogramming)
  • Provide a specialized StringBuilder and suite of helpers, CodeBuilder?

Project: Array types

  • Add fixed length array types: Array[<type expr> x <int literal>]

Project: Defer

  • Defer

Project: static reflection

  • Runtime type info story
  • typeOf, typeId
  • TypeSchema for all types
  • Test 'Any' type

Project: Operator overloading

  • Operator 'overloading' story. I think the story is just abilities. This will actually fix the really poor inference that binary ops currently have
  • Start with Equals
  • Do add
  • Move all the binary operations to intrinsic calls; and remove BinaryOp from the Typed AST

Working list (early 2025)

  • String pool for string values, not just identifiers (will dedupe in LLVM too)
  • Adopt ecow's EcoVec
  • reproduce shadow bug: only when statically run?! buffer.slice: let end = if end > self.len self.len else end;
  • Fix referencing match not 'eliminating' patterns on struct* giving unhandled pattern .CustomHeap({ zalloc }*) -> {
  • Optimize lambdas that don't capture to become function pointers instead
  • comptime #if needs to be a real node not a directive (can't parse if/else). More like #const if than #if
  • string interp at end puts unnecessary empty string part: putString(__sb_1001, "");
  • Backend codegen cleanup
  • avoid uses of aggregate values where we can: so routine uses of 'struct's and 'enum's
  • Move allocas to entry block. "Doing this is actually quite easy as LLVM provides functions you can use to retrieve the entry block for a function and insert instructions into it." (handled by optimization passes for now)
  • Upgrade to LLVM 18
  • Context location params are not being propagated
  • Test and fix named arguments
  • 'never' needs to work in every expression position (got close enough, might add more if one comes up) -> Originally did the wrong way, plumbing special cases. Instead now we just only generate the crashy expr
  • accumulate test errors and support inline test comment assertions when a line should produce a compiler error. - Probably one test for failing compilation and one passing one for each major language area
  • Add simple int range in stdlib
  • Fix enum codegen, read Inko llvm backend (its inkwell + rust and does ABI compatible stuff https://yorickpeterse.com/articles/the-mess-that-is-handling-structure-arguments-and-returns-in-llvm/)
  • Conditional compile directive
  • Support boolean operators in compile time expressions
  • Change FieldAccess semantics to work on struct references, and copy only the field out This saves copying the entire aggregate first with a Dereference instruction
  • ThreadLocal globals
  • LLVM Codegen callstack is too deep due to codegen_function_or_get
  • Switch VM stack to a single virtual allocation https://crates.io/crates/memmap2
  • Improve LLVM opt pipeline https://www.reddit.com/r/Compilers/comments/1hqmd7x/recommended_llvm_passes/ https://llvm.org/docs/NewPassManager.html#just-tell-me-how-to-run-the-default-optimization-pipeline-with-the-new-pass-manager
  • Stacktraces on crash (using libunwind and a little C program to call it: rt/unwind.c)
  • [-] Write a 'validateTypedModule' procedure. This need is lessened by the VM which in a way typechecks the TAST This is basically an interpreter; what we have now with the vm solves this problem a bit But not entirely because it only checks the code that runs!

General (late 2024)

  • Matching push
    • boolean chains w/ binding ifs
    • Don't codegen conditions for arms that don't run
    • Remove 'statement conditions'
    • Prevent shadowing
    • Rewrite codegen for match to allow for better control flow
    • 'if' guards on regular match
    • Move pattern bindings for field access and enum payload back to variables to fully remove duplication (we can do this now that we have a place to put them that's per-arm)
    • Look into converting 'matching if' to also compile to a TypedMatch
    • Binding while
    • Matching on references
      • Match to get reference to each struct field, for example, use * for a dereferencing match
      • Match to get reference to enum payload
    • ASSERT FAILED: true != true at core.k1:23
  • Real type inference
    • True inference variables, instantiate function types, unification and consistency checks, aka make it work
    • Make 'crash' work in no-std
    • Make it pretty (de-coupled inference hole from type variable)
    • Move enum constructor onto new inference infra
    • Move ability resolution onto new inference infra
    • Make it fast (Added better 'pool' to prepare for avoiding lots of allocations)
  • Fix closure types / get static dispatch for functions taking a closure directly
  • Specializing functions on their provided closures to allow inlining and static dispatch
  • Run in Linux x86-64
  • require statements with matching and binding
  • Runtime-branching Allocator system (v2 is comptime branching)
    • comptime enhancement to support this global initializer: let* a: Arena* = { .. };
    • Global pointers, to enable
    • The problem with passing an allocator around is all code becomes generic, or casts a pointer.
    • Comptime structs!
    • alloca in loops fix
    • Parameterize stdlib over the current allocator ()
  • Proper basic comptime
    • Rename to 'static'
    • Move to stack-based VM
    • literals
    • if/else
    • Arith
    • Struct construction
    • Struct field access
    • Enum construction

Non-goals at least for now

  • Memory safety / solving the 'aliasing' problem, not because its unimportant but because I have other interests
  • Tuples. I don't think you need them if you have anonymous structs. The lack of names always makes them easy to start using and very hard to maintain / read consumer code. "In the beginning all you want is an anonymous tuple and in the end all you want are named fields"
  • Ability derivation (prefer a metaprogram solution)

Won't do

  • Replace 'unit' with an empty struct, encoded as {} at the type level and {} at the value level. This would remove a whole base type This simplification comes at the cost of making empty struct quite special, so I think it's a sidegrade. Won't do
  • 'call' method syntax (Scala's 'apply' feature)

Ideas

  • 'join' types to form new enums/structs, statically. switch {strict|dynamic} ...? If dynamic, I'll build a sum or product based on the branches' types
  • Might be very cool to have builtin syntax for anything implementing a 'Monad' ability
    • (Monad ability would require closures and generic abilities, which we now have. Just need higher order type params F[_]
  • Require named fncall args by default; and allow anonymous w/ declaration like Jakt?
  • Test handling of NaN and Infinity, other float edge cases
  • Try to encode prefix strings, aka German/Umbra strings

Compiler

  • LLVM: avoid loading aggregate values directly
  • Convert NamedType to a trait
  • Use smallvec
  • UTF8
  • Test multi-byte characters (emoji, other)
  • Intern ParsedBlock and ParsedStatement

Error story

  • As values, of course.
  • A simple stdlib enum?
  • A '?' operator for early return? We could do an ability for it!

Memory Management story

  • Semi-auto, mostly arenas, perhaps 2 global ones, 'perm' and 'tmp' via thread-locals, standard library built around them

Major fix

  • Unmatched closing delim in namespace causes silent failure to parse rest of sources
  • Parsing bug where first expr of block is namespaced with ::
  • Parsing bug where if rest.startsWith("one") .Some(1: u64) parses as if rest.startsWith("one").Some(1: u64)
  • ICE when assigning to struct member when struct is not a reference (self.module.types.get(field_access.base.get_type()).as_reference().is_some())
  • Require indirection for recursive types; and make them actually really work

Minor Fix (possible good bite-sized videos)

  • Lexer cleanup > Am I crazy or is this just always tok_buf.len()?!?!?!
  • Binary op inference improvements
    • assert(sizeOfText == 16 + 32); rhs should infer to u64
  • Precedence of dereference (and i guess unary ops in general) should be higher Kinda fixed by removing all unary ops except 'not'

GUI checklist

  • Get render loop working with access to module, ability to trigger compile, run
  • Render namespaces, use recursion over namespace for all functionality?
  • Search for a type?
  • One day allow updating or adding a single definition

2024

  • Fixing enums big time

    • Rename Optional -> Opt
    • Remove tag literals, make enum tags per-enum
    • Parse type expr Opt[T].Some
    • expr Opt.None
    • expr _root::Opt.None
    • expr _root::Opt.None[i32]
    • expr Opt.Some(5)
    • expr Opt.Some[i32](5)
    • expr _root::Opt.Some[i32](5)
    • deal with fncall syntax collision by checking for the enum first
    • kill ParsedTypeExpression::AnonEnumVariant?
    • CastType EnumVariant: checks should not happen in codegen
    • Convert TypedIf.consequent and TypedIf.alternative to TypedExpr from TypedBlock
  • QoL before rest of pattern matching

    • Codegen fail instead of panic
    • Rename record to struct
    • Start gui
    • Remove ! for negation; switch to 'not'
  • Get LLVM interpreter working (for test suite)

  • 'crash' w/ line no for option unwrap

  • 'crash' w/ line no for bad enum cast

  • Match expected errors from test programs

  • 'never' type

    • typechecking / codegen
    • if/else
    • match
  • Pattern Matching

    • Single-arm match evals to boolean
    • Literals
    • Variables
    • Optional None
    • Optional Some
    • Make sure binary AND doesn't evaluate its rhs if lhs is false!
    • Records
    • Enums
    • Multi-case
  • Enum types (enums / tagged unions)

    • Syntax
    • Construction/repr - [x] Later, pattern match on variants
    • Make first-class types for each variant
    • First, hard cast to variant (as<.Tag>)
    • Built-in .as or panic
    • syntax: optional pipe separator
    • Enum methods
  • Type cleanup

    • Order of eval (topology through defer/skip)
    • named struct and enum fix
    • Newtypes (opaque)
    • Aliases
  • Generic structs and enums

  • Recursive types

  • TypedIf allow exprs instead of requiring blocks (did not do; instead improved handling of unit blocks)

  • Remove binding 'if' since we have pattern matching

  • Abilities

  • Ability impl decl order bugfix (ability impls need to be seen in the decl phase)

  • Type Ascriptions

  • Enforce unique function name in namespace!

  • Optional coalescing binary operator '?'

  • Raw Pointer

    • from int64
    • to int64
    • from reference
    • to reference
  • sizeOf

  • Rest of the int sizes

    • 8
    • 16
    • 32
    • 64
    • reject invalid values
    • implement infallible coercions
    • implement cast
    • hex literals?
    • binary literals?
  • Reject too many function args

  • Use abilities to implement Bits namespace

  • return statement (control flow of blocks / statements: CanReturn, AlwaysReturns, NeverReturns (which is 'never')) ^ mixed feelings here as it breaks the fact that 'expr as T' always returns a T...

  • Use as casting syntax for rawpointer.asUnsafe

  • Allow as casting syntax for enums to supply only the tag (result as .Ok instead of result as Result<T,E>.Ok)

  • Ability constraints on functions

  • Remove custom size/align code and use LLVM's

  • More type expressions! (this was a big part of my original point)

    • Intersect structs
    • Union structs
    • inner type of optional
    • return type of function (fn.return)
    • param types of function (fn.arg, fn.arg2)
  • Exhaustive pattern matching

  • Rework RawPointer to be a builtin and support 'multipointer' operations

  • Pipe operator (copy Elixir)

  • Rework builtin array to use new Pointer, Remove all array intrinsics and builtin type

    • Add array bounds checking
    • Fix array literal syntax
  • Rework builtin string to use new Pointer

  • Rework builtin optionals to be a generic enum

  • floating point (f32 and f64)

  • 'Context' system; implicit stack arguments

  • Pass caller source location for assert

  • Function types (functions have types but there's no syntax for describing a function type yet)

  • Optional coalescing field accessor (x?.y)

  • function pointers (By taking the static address of a function as Pointer)

  • Finish/fix simple generic inference

  • Prevent function overloading in same namespace

  • Typecheck the binary ops

  • Bitwise ops

  • Bitwise ops using abilities

  • Closures

    • Direct calls, no captures
    • Support captures, but explicit only
    • Support implicit captures
    • Allow 0 args
    • Allow specifying return type (without typing the closure itself)
    • Return works
  • Change reference and dereference syntax to x.& and x.*

  • Fix context params when combined with generics

  • string interpolation

  • typeOf()

  • Remove coercion from the language (only dereference is left)

  • Rework Opaques

    • Just use structs with private fields
  • Working with references push, specifically struct and either references

    • A nice syntax for referenceSet
    • New assignment operator, not = (<-)
    • Make EnumGetPayload a valid lhs?
    • Kill .& because so unsound, use let* for those cases
      • Not the worst thing to use let* for the c-interop case of needing a pointer, that's what .& was doing anyway
    • EnumGetPayload on a reference doesn't give a reference (and shouldn't always, what syntax to specify)
    • FieldAccess on a reference doesn't give a reference (and shouldn't always, what syntax to specify)
  • Array/Slice/string rework to Buffer/List, and eventually Array (fixed size at compile time)

  • Do away with k1lib.c?

  • Test Struct shorthand syntax

  • Imports

    • types
    • functions
    • constants
    • namespaces
  • Ability call resolution rework

    • Remove restriction that first arg is Self by
    • Reworking resolution to find a function by name first, then Solve for 'self' by unifying call and signature, then find the impl
  • Fully generic abilities with separate 'input' vs 'output' type parameters

  • Blanket ability implementations

  • nocompile() intrinsic! yields an actual runtime constant string for assertions?! let result1 = compiler/nocompile(1 + "asdf"); assert(result1.startsWith("Type mismatch"))

  • Migrate ? to use an ability

  • Add "or return error" operator based on an ability

  • Convert try to postfix: hello.try (hearkening to .await)

  • ! operator should now just call Unwrap.unwrap()

  • Bug: if a blanket impl fails to typecheck, we should not use it. Currently we ice trying to instantiate it

  • Migrate for loops to use a core Iterator ability

  • Namespace stuff

    • Imports via use
    • Change keyword to ns
    • namespace <ident>; to namespace whole file
    • Allow namespace extension via simple multiple blocks of same name in same scope
  • Re-write signature specialization to be simpler.

  • return from while

  • break from while

  • Move tests into fewer files

  • Finish hashmap implementation

  • Handle escaped chars in string literals

  • Friendliness pass

    • Replace 'enum' keyword with 'either', ensure the ambiguous cases have good errors (inside struct, inside param list)
    • 'when' keyword is bad; switch maybe or case, or resolve the ambiguity with when <x> is {}
    • Replace type with deftype - It would be really nice not to take the keyword 'type'. Just a thought from using Rust/Scala
  • Remove tag literals, make enum tags per-enum

  • Ability-based iteration

Old todo list

  • Records

    • Syntax decision ({} vs .{} vs Point {})
    • Parsing
    • Typechecking
    • codegen static as LLVM structs
    • Accessor syntax
    • Accessor ir
    • Accessor codegen
  • Identifier cleanup and interning

  • Actual scoping

  • Real core so we can more easily add runtime/stl functions (for array)

  • Heap memory (just using malloc)

  • Arrays (Fixed size but heap allocated)

  • Generic functions (no inference)

  • Remove / fix TokenIter type

  • parens around expressions

  • Binary infix operations

  • basic error reporting using spans

  • Array and Struct member assignment

  • While Loop

  • Assert (syscall exit? 'panic'?)

  • Replace .length on string and array with a MethodCall node (adding empty parens ())

  • Change Array repr to a struct w/ length so we have length

  • Strings

    • String literals cant have spaces lol
    • print(string)
    • hardcoded via codegen
    • string.length
    • string[i] (int)
    • char
    • string[i] (char)
    • add string.length function
    • char.to_string()
  • Concatenate strings (in userland; slow)

  • Infer let types

  • Extern keyword, then

  • Link at build time not via LLVM module

  • Use ctx.const_string for printf format strings

  • Optionals

  • Improve printing output by fixing display functions

  • Implement builtin growable array

  • Use aggregates in codegen, not pointers, for optionals

  • Basic generic type inference in function calls

  • Pretty print scopes

  • Support multiple files

  • Fix namespaces to require full paths (currently busted must be unique names globally)

  • Allow namespaces inside namespaces

  • Some debug info in LLVM IR (source snippets or line numbers?)

  • uint type

  • Generic type inference

  • Type literals would be fun

  • Syntax Shed

    • Function syntax change? (foo = fn (a, b, c): int { }
    • from qualifier-focused to name -focused
    • Parse trailing commas
  • [-] For iteration (we will just hardcode the iterable types)

    • 'do' version
    • 'yield' version on array
    • 'yield' version on string
    • Provide index var (it_index)
  • DEBUG info

    • on or off
    • flag types
    • correct line nums
    • correct spans (depends on multifile)
    • correct file path
    • Add lexical scopes for if and while

Optionals

  • Optional types
  • None types
  • None value
  • Runtime repr for boolean
  • Runtime repr for unit
  • Runtime repr for int
  • Runtime repr for char
  • Runtime repr for string
  • struct
  • array of optional structs

Optionals Round 2

  • move some-wrapping into a function
  • has value from userland (currently only happens by desugaring))
  • unwrap from userland (I think this can just be a core function not intrinsic)
  • test with optional array elements
  • test with optional struct fields
  • test with optional function args
  • Explicit Some() expression

Dogfood wishlist Oct23

  • I really need a way to write code in Zig or C and use it in my stl to move things along
  • Zig binding of my Array
  • Early return
  • Implicit return of unit if no return statement
  • string.indexOf
    • charToString implemented in zig and linked
  • Array.distinct in zig
  • Not equal != operator
  • Unary negation operator

Fibonacci todos (Aug 23)

  • Equality binop
  • Precedence of binops; parens?
  • Recursion fix: process module decls first, then impls
  • Negative integer literals
  • PHI nested branch fix

Hacks to fix

  • Fix line comments
  • Maybe eventually actually free some memory? lol
  • Rename IR to typed-ast, since it's a tree not instruction set. TAST?
  • Make intrinsics like arrayIndex a real function in the LLVM IR?
  • Fix line numbers to account for core
  • Fix unnecessary load of function args
  • Proper println implementation. Fine to use printf internally for now but we should define our own func around it
  • Implement Display instead of relying on Debug

Dev ex

  • Pretty-print AST
  • Error Spans
  • fancy output COLORS

Maybe later

  • Type Params

Resurrect project (March '23)

  • Implement typed IR
  • Implement FnCall
  • Implement Add
  • Implement Multiply
  • Use basicvalue not pointervalue as main IR type
  • Add booleans
  • Add boolean AND and OR
  • Parse line comments
  • implement "expected output" for test sources
  • Add spans to AST
  • Add spans to IR
  • Implement IF expressions