//: Structured programming //: //: Our jump recipes are quite inconvenient to use, so mu provides a //: lightweight tool called 'transform_braces' to work in a slightly more //: convenient format with nested braces: //: //: { //: some instructions //: { //: more instructions //: } //: } //: //: Braces are just labels, they require no special parsing. The pseudo //: recipes 'loop' and 'break' jump to just after the enclosing '{' and '}' //: respectively. //: //: Conditional and unconditional 'loop' and 'break' should give us 80% of the //: benefits of the control-flow primitives we're used to in other languages, //: like 'if', 'while', 'for', etc. :(scenarios transform) :(scenario brace_conversion) def main [ { break 1:number <- copy 0 } ] +transform: --- transform braces for recipe main +transform: jump 1:offset +transform: copy ... :(before "End Instruction Modifying Transforms") Transform.push_back(transform_braces); // idempotent :(code) void transform_braces(const recipe_ordinal r) { const int OPEN = 0, CLOSE = 1; // use signed integer for step index because we'll be doing arithmetic on it list<pair<int/*OPEN/CLOSE*/, /*step*/int> > braces; trace(9991, "transform") << "--- transform braces for recipe " << get(Recipe, r).name << end(); //? cerr << "--- transform braces for recipe " << get(Recipe, r).name << '\n'; for (int index = 0; index < SIZE(get(Recipe, r).steps); ++index) { const instruction& inst = get(Recipe, r).steps.at(index); if (inst.label == "{") { trace(9993, "transform") << maybe(get(Recipe, r).name) << "push (open, " << index << ")" << end(); braces.push_back(pair<int,int>(OPEN, index)); } if (inst.label == "}") { trace(9993, "transform") << "push (close, " << index << ")" << end(); braces.push_back(pair<int,int>(CLOSE, index)); } } stack</*step*/int> open_braces; for (int index = 0; index < SIZE(get(Recipe, r).steps); ++index) { instruction& inst = get(Recipe, r).steps.at(index); if (inst.label == "{") { open_braces.push(index); continue; } if (inst.label == "}") { if (open_braces.empty()) { raise << "missing '{' in '" << get(Recipe, r).name << "'\n" << end(); return; } open_braces.pop(); continue; } if (inst.is_label) continue; if (inst.old_name != "loop" && inst.old_name != "loop-if" && inst.old_name != "loop-unless" && inst.old_name != "break" && inst.old_name != "break-if" && inst.old_name != "break-unless") { trace(9992, "transform") << inst.old_name << " ..." << end(); continue; } // check for errors if (inst.old_name.find(discard """ output: ''' we direct generic generic ''' joinable: false """ import algorithm, sugar, sequtils, typetraits, asyncdispatch block tconfusing_arrow: type Deck = object value: int proc sort(h: var seq[Deck]) = # works: h.sort(proc (x, y: Deck): auto = cmp(x.value, y.value)) # fails: h.sort((x, y: Deck) => cmp(ord(x.value), ord(y.value))) var player: seq[Deck] = @[] player.sort() block tdictdestruct: type TDict[TK, TV] = object k: TK v: TV PDict[TK, TV] = ref TDict[TK, TV] proc fakeNew[T](x: var ref T, destroy: proc (a: ref T) {.nimcall.}) = discard proc destroyDict[TK, TV](a: PDict[TK, TV]) = return proc newDict[TK, TV](a: TK, b: TV): PDict[TK, TV] = fakeNew(result, destroyDict[TK, TV]) # Problem: destroyDict is not instantiated when newDict is instantiated! discard newDict("a", "b") block tgenericdefaults: type TFoo[T, U, R = int] = object x: T y: U z: R TBar[T] = TFoo[T, array[4, T], T] var x1: TFoo[int, float] static: assert type(x1.x) is int assert type(x1.y) is float assert type(x1.z) is int var x2: TFoo[string, R = float, U = seq[int]] static: assert type(x2.x) is string assert type(x2.y) is seq[int] assert type(x2.z) is float var x3: TBar[float] static: assert type(x3.x) is float assert type(x3.y) is array[4, float] assert type(x3.z) is float block tprop: type TProperty[T] = object of RootObj getProc: proc(property: TProperty[T]): T {.nimcall.} setProc: proc(property: TProperty[T], value: T) {.nimcall.} value: T proc newProperty[T](value: RootObj): TProperty[T] = result.getProc = proc (property: TProperty[T]) = return property.value block trefs: type PA[T] = ref TA[T] TA[T] = object field: T var a: PA[string] new(a) a.field = "some string" proc someOther[T](len: string): seq[T] = discard proc someOther[T](len: int): seq[T] = echo "we" proc foo[T](x: T) = var s = someOther[T](34) #newSeq[T](34) foo 23 when false: # Compiles unless you use var a: PA[string] type PA = ref TA TA[T] = object # Cannot instantiate: type TA[T] = object a: PA[T] PA[T] = ref TA[T] type PA[T] = ref TA[T] TA[T] = object block tsharedcases: proc typeNameLen(x: typedesc): int {.compileTime.} = result = x.name.len macro selectType(a, b: typedesc): typedesc = result = a type Foo[T] = object data1: array[T.high, int] data2: array[typeNameLen(T), float] data3: array[0..T.typeNameLen, selectType(float, int)] MyEnum = enum A, B, C, D var f1: Foo[MyEnum] var f2: Foo[int8] doAssert high(f1.data1) == 2 # (D = 3) - 1 == 2 doAssert high(f1.data2) == 5 # (MyEnum.len = 6) - 1 == 5 doAssert high(f2.data1) == 126 # 127 - 1 == 126 doAssert high(f2.data2) == 3 # int8.len - 1 == 3 static: assert high(f1.data1) == ord(C) assert high(f1.data2) == 5 # length of MyEnum minus one, because we