diff --git a/neat.html.markdown b/neat.html.markdown deleted file mode 100644 index f02461ee..00000000 --- a/neat.html.markdown +++ /dev/null @@ -1,297 +0,0 @@ ---- -language: neat -contributors: - - ["Feep", "https://github.com/FeepingCreature"] -filename: LearnNeat.nt ---- - -Neat is basically a smaller version of D1 with some experimental syntax and a focus on terseness without losing the basic C-like syntax. - -[Read more here.](https://github.com/FeepingCreature/fcc/wiki) - -```c -// single line comments start with // -/* - multiline comments look like this -*/ -/+ - or this - /+ these can be nested too, same as D +/ -+/ - -// Module name. This has to match the filename/directory. -module LearnNeat; - -// Make names from another module visible in this one. -import std.file; -// You can import multiple things at once. -import std.math, std.util; -// You can even group up imports! -import std.(process, socket); - -// Global functions! -void foo() { } - -// Main function, same as in C. -// string[] == "array of strings". -// "string" is just an alias for char[], -void main(string[] args) { - // Call functions with "function expression". - writeln "Hello World"; - // You can do it like in C too... if you really want. - writeln ("Hello World"); - // Declare a variable with "type identifier" - string arg = ("Hello World"); - writeln arg; - // (expression, expression) forms a tuple. - // There are no one-value tuples though. - // So you can always use () in the mathematical sense. - // (string) arg; <- is an error - - /* - byte: 8 bit signed integer - char: 8 bit UTF-8 byte component. - short: 16 bit signed integer - int: 32 bit signed integer - long: 64 bit signed integer - - float: 32 bit floating point - double: 64 bit floating point - real: biggest native size floating point (80 bit on x86). - - bool: true or false - */ - int a = 5; - bool b = true; - // as in C, && and || are short-circuit evaluating. - b = b && false; - assert(b == false); - // "" are "format strings". So $variable will be substituted at runtime - // with a formatted version of the variable. - writeln "$a"; - // This will just print $a. - writeln `$a`; - // you can format expressions with $() - writeln "$(2+2)"; - // Note: there is no special syntax for characters. - char c = "a"; - // Cast values by using type: expression. - // There are three kinds of casts: - // casts that just specify conversions that would be happening automatically - // (implicit casts) - float f = float:5; - float f2 = 5; // would also work - // casts that require throwing away information or complicated computation - - // those must always be done explicitly - // (conversion casts) - int i = int:f; - // int i = f; // would not work! - // and, as a last attempt, casts that just reinterpret the raw data. - // Those only work if the types have the same size. - string s = "Hello World"; - // Arrays are (length, pointer) pairs. - // This is a tuple type. Tuple types are (type, type, type). - // The type of a tuple expression is a tuple type. (duh) - (int, char*) array = (int, char*): s; - // You can index arrays and tuples using the expression[index] syntax. - writeln "pointer is $(array[1]) and length is $(array[0])"; - // You can slice them using the expression[from .. to] syntax. - // Slicing an array makes another array. - writeln "$(s[0..5]) World"; - // Alias name = expression gives the expression a name. - // As opposed to a variable, aliases do not have an address - // and can not be assigned to. (Unless the expression is assignable) - alias range = 0 .. 5; - writeln "$(s[range]) World"; - // You can iterate over ranges. - for int i <- range { - write "$(s[i])"; - } - writeln " World"; - // Note that if "range" had been a variable, it would be 'empty' now! - // Range variables can only be iterated once. - // The syntax for iteration is "expression <- iterable". - // Lots of things are iterable. - for char c <- "Hello" { write "$c"; } - writeln " World"; - // For loops are "for test statement"; - alias test = char d <- "Hello"; - for test write "$d"; - writeln " World\t\x05"; // note: escapes work - // Pointers: function the same as in C, btw. The usual. - // Do note: the pointer star sticks with the TYPE, not the VARIABLE! - string* p; - assert(p == null); // default initializer - p = &s; - writeln "$(*p)"; - // Math operators are (almost) standard. - int x = 2 + 3 * 4 << 5; - // Note: XOR is "xor". ^ is reserved for exponentiation (once I implement that). - int y = 3 xor 5; - int z = 5; - assert(z++ == 5); - assert(++z == 7); - writeln "x $x y $y z $z"; - // As in D, ~ concatenates. - string hewo = "Hello " ~ "World"; - // == tests for equality, "is" tests for identity. - assert (hewo == s); - assert !(hewo is s); - // same as - assert (hewo !is s); - - // Allocate arrays using "new array length" - int[] integers = new int[] 10; - assert(integers.length == 10); - assert(integers[0] == 0); // zero is default initializer - integers = integers ~ 5; // This allocates a new array! - assert(integers.length == 11); - - // This is an appender array. - // Instead of (length, pointer), it tracks (capacity, length, pointer). - // When you append to it, it will use the free capacity if it can. - // If it runs out of space, it reallocates - but it will free the old array automatically. - // This makes it convenient for building arrays. - int[auto~] appender; - appender ~= 2; - appender ~= 3; - appender.free(); // same as {mem.free(appender.ptr); appender = null;} - - // Scope variables are automatically freed at the end of the current scope. - scope int[auto~] someOtherAppender; - // This is the same as: - int[auto~] someOtherAppender2; - onExit { someOtherAppender2.free; } - - // You can do a C for loop too - // - but why would you want to? - for (int i = 0; i < 5; ++i) { } - // Otherwise, for and while are the same. - while int i <- 0..4 { - assert(i == 0); - break; // continue works too - } then assert(false); // if we hadn't break'd, this would run at the end - // This is the height of loopdom - the produce-test-consume loop. - do { - int i = 5; - } while (i == 5) { - assert(i == 5); - break; // otherwise we'd go back up to do { - } - - // This is a nested function. - // Nested functions can access the surrounding function. - string returnS() { return s; } - writeln returnS(); - - // Take the address of a function using & - // The type of a global function is ReturnType function(ParameterTypeTuple). - void function() foop = &foo; - - // Similarly, the type of a nested function is ReturnType delegate(ParameterTypeTuple). - string delegate() returnSp = &returnS; - writeln returnSp(); - // Class member functions and struct member functions also fit into delegate variables. - // In general, delegates are functions that carry an additional context pointer. - // ("fat pointers" in C) - - // Allocate a "snapshot" with "new delegate". - // Snapshots are not closures! I used to call them closures too, - // but then my Haskell-using friends yelled at me so I had to stop. - // The difference is that snapshots "capture" their surrounding context - // when "new" is used. - // This allows things like this - int delegate(int) add(int a) { - int add_a(int b) { return a + b; } - // This does not work - the context of add_a becomes invalid - // when add returns. - // return &add_a; - // Instead: - return new &add_a; - } - int delegate(int) dg = add 2; - assert (dg(3) == 5); - // or - assert (((add 2) 3) == 5); - // or - assert (add 2 3 == 5); - // add can also be written as - int delegate(int) add2(int a) { - // this is an implicit, nameless nested function. - return new λ(int b) { return a + b; } - } - // or even - auto add3(int a) { return new λ(int b) -> a + b; } - // hahahaaa - auto add4 = λ(int a) -> new λ(int b) -> a + b; - assert(add4 2 3 == 5); - // If your keyboard doesn't have a λ (you poor sod) - // you can use \ too. - auto add5 = \(int a) -> new \(int b) -> a + b; - // Note! - auto nestfun = λ() { } // There is NO semicolon needed here! - // "}" can always substitute for "};". - // This provides syntactic consistency with built-in statements. - - - // This is a class. - // Note: almost all elements of Neat can be used on the module level - // or just as well inside a function. - class C { - int a; - void writeA() { writeln "$a"; } - // It's a nested class - it exists in the context of main(). - // so if you leave main(), any instances of C become invalid. - void writeS() { writeln "$s"; } - } - C cc = new C; - // cc is a *reference* to C. Classes are always references. - cc.a = 5; // Always used for property access. - auto ccp = &cc; - (*ccp).a = 6; - // or just - ccp.a = 7; - cc.writeA(); - cc.writeS(); // to prove I'm not making things up - // Interfaces work same as in D, basically. Or Java. - interface E { void doE(); } - // Inheritance works same as in D, basically. Or Java. - class D : C, E { - override void writeA() { writeln "hahahahaha no"; } - override void doE() { writeln "eeeee"; } - // all classes inherit from Object. (toString is defined in Object) - override string toString() { return "I am a D"; } - } - C cd = new D; - // all methods are always virtual. - cd.writeA(); - E e = E:cd; // dynamic class cast! - e.doE(); - writeln "$e"; // all interfaces convert to Object implicitly. - - // Templates! - // Templates are parameterized namespaces, taking a type as a parameter. - template Templ(T) { - alias hi = 5, hii = 8; - // Templates always have to include something with the same name as the template - // - this will become the template's _value_. - // Static ifs are evaluated statically, at compile-time. - // Because of this, the test has to be a constant expression, - // or something that can be optimized to a constant. - static if (types-equal (T, int)) { - alias Templ = hi; - } else { - alias Templ = hii; - } - } - assert(Templ!int == 5); - assert(Templ!float == 8); -} -``` - -## Topics Not Covered - - * Extended iterator types and expressions - * Standard library - * Conditions (error handling) - * Macros