diff --git a/spec.txt b/spec.txt index fa405f6..4a358f3 100644 --- a/spec.txt +++ b/spec.txt @@ -50,7 +50,7 @@ Literals: 'a' -> u8 (ascii only?) '猫'u -> u32 -TODO: string literals? fixed-size arrays? built-in spans? Probably built-in spans (potentially defined in prelude.psl) +// TODO: string literals? fixed-size arrays? built-in spans? Probably built-in spans (defined in prelude.psl) "hello, world" -> utf-8 string "здарова, братки"u -> utf-32 string @@ -72,7 +72,7 @@ Array declaration: Null pointer literal: let p: u32* = null // special like empty array literal, type cannot be inferred -Variables must always be initialized. (TODO: really? What about arrays? Maybe need special syntax for zero-initialization or mass-initialization. Alternative: default to zero-initialization) +Variables must always be initialized. // TODO: really? What about arrays? Maybe need special syntax for zero-initialization or mass-initialization. Alternative: default to zero-initialization Const variables must be initialized with a const expression (any expression that doesn't include non-const values). ======== OPERATORS ======== @@ -126,7 +126,7 @@ Casting: The only implicit casting allowed is T mut* -> T* (maybe?) Any integer/floating-point types can be cast to each other. -Any pointer types can be cast to each other (TODO: alignment? UB or safe fallback? Probably UB.) +Any pointer types can be cast to each other // TODO: alignment? UB or safe fallback? Probably UB. Ternary if operator: if condition then true_value else false_value @@ -150,7 +150,7 @@ Special built-ins: ======== FLOW CONTROL ======== -Flow control: +Conditionals: if condition: statements else if condition: @@ -158,6 +158,7 @@ Flow control: else: statements +While loop: while condition: statements if x: @@ -165,7 +166,38 @@ Flow control: if y: continue - TODO: for loops? iterator/range interface? +Iterator interface: + get(it) returns the currently pointed-to value + get_ref(it) returns the pointer to the currently pointed-to value + next(it) returns the next iterator + +Range interface: + begin(range) returns the begin iterator + end(range) returns the end iterator + +For loop: + Operates only on ranges. + + for x in range(10): + do_something(x) + + i is immutable within the loop body. + + Modifiable ranges use special syntax for pointers to elements: + + for &x in array: + *x += 1 + + The loop is equivalent to + + mut begin = begin(range) + let end = end(range) + while begin != end: + let x = get(begin) // or get_ref(x) for pointer loop + statements + begin = next(begin) + + The prelude contains an implementation of range interface for built-in arrays. ======== STRUCTS ======== @@ -184,7 +216,7 @@ Struct field access: let p = &r let y = p.height // field access through pointer is the same -TODO: inner struct functions maybe? to act as namespace/module containers +// TODO: inner struct functions maybe? to act as namespace/module containers ======== FUNCTIONS ======== @@ -195,12 +227,37 @@ Function definition: func bar(x: f32): // deduced return type unit print(x) + Function arguments are automatically immutable (as if declared with let). + // External function: name taken literally as `powf` // and C calling convention assumed foreign func powf(x: f32, y: f32) -> f32 // no implementation -TODO: function overloading? Probably requires selecting a specific overload using `as` operator to save to a value (but not on call site) -TODO: alternative - Rust-like traits? More powerful, but complicates the language +// TODO: mutable function arguments? + +// TODO: function overloading? Probably requires selecting a specific overload using `as` operator to save to a value (but not on call site) +// TODO: alternative - Rust-like traits, aka parametric polymorphism? + +======== TEMPLATES ======== + +// TODO +// Definitely monomorphized. +// Parametric (C++ templates) vs ad-hoc (Rust traits, Haskell typeclasses)? +// +// Ad-hoc: +// + More powerful +// + Less concepts in the core language +// + Simpler to use in basic cases +// - Bad error messages (can be improved with concepts) +// - Slow compilation (due to type-checking each instantiation) +// +// Parametric: +// + Cleaner, stricter +// + Faster compilation (type-checking only once) +// + Better error messages +// - Less powerful +// - Harder to use in basic cases (e.g. have to declare type constraints or create new traits for any desired per-type behavior) +// - A bunch of new required language concepts (trait, impl, constraint), much more complicated to implement in compiler ======== TYPE OF TYPES ======== @@ -233,10 +290,50 @@ E.g. // else: // return y +======== PRELUDE ======== + +Prelude is a special source file implicitly included in any project (unless explicitly requested otherwise). + +It contains: + + An array_view template struct: + + struct array_view: + size: u64 + data: t* + + A specialization for strings: + + const string_view = array_view + + (String literals compile into string_view objects.) + + Range interface for built-in arrays and for array_view. + + Numeric ranges with signatures + + range(end) // begin implicitly zero + range(begin, end) // step implicitly one + range(begin, end, step) + + that allow iteration like + + for i in range(10): + for i in range(5u, 10u): + for i in range(1.0, 10.0, 0.5): + ======== MODULES AND IMPORTS ======== // TODO +// A build system / package metadata? How to e.g. conditionally add some files based on environment (maybe just forbid that)? +// How to describe platform-dependent behavior? +// * Different files - who decides which files to include? +// * Compile-time built-ins - how flexible are they? +// Can we create a different type based on platform? +// Important for some posix stuff like timespec or threads +// * Special compiler intrinsics/attributes/macros/whatever - need a new concept in the language +// Maybe a good thing - can merge with alignment specification and other stuff ======== STANDARD LIBRARY ======== -// TODO: containers, memory management, strings? +// TODO: containers, memory management, strings, io, math, threads, networking(?)