root/trunk/samples/simple.md

Revision 437, 10.3 kB (checked in by JarrettBillingsley, 1 week ago)

Split the io lib into an "unsafe" io portion and the new safe stream library. Streams are just fine as long as they're not hooked up to something bad!

(I've got plans to use them too.)

Line 
1 module samples.simple
2
3
4
5 /+
6 // Making sure finally blocks are executed.
7 {
8     local function f()
9     {
10         try
11         {
12             try
13             {
14                 writefln("hi 1")
15                 return "foo", "bar"
16             }
17             finally
18                 writefln("bye 1")
19
20             writefln("no use 1")
21         }
22         finally
23             writefln("bye 2")
24
25         writefln("no use 2")
26     }
27
28     local a, b = f()
29     writefln(a, ", ", b)
30
31     writefln()
32 }
33
34 // Importing stuff.
35 {
36     modules.customLoaders.mod = function loadMod(name: string)
37     {
38         assert(name == "mod")
39
40         global x = "I'm x"
41
42         global function foo()
43             writefln("foo")
44
45         global function bar(x) = x[0]
46
47         global function baz()
48             writefln(x)
49     }
50
51     import mod: foo, bar
52     foo()
53     writefln(bar([5]))
54     mod.baz()
55
56     writefln()
57 }
58
59 // Super calls.
60 {
61     local class Base
62     {
63         function fork()
64             writefln("Base fork.")
65     }
66
67     local class Derived : Base
68     {
69         function fork()
70         {
71             writefln("Derived fork!")
72             super.fork()
73         }
74     }
75
76     local d = Derived()
77     d.fork()
78
79     writefln()
80 }
81
82 // Coroutines and coroutine iteration.
83 {
84     local countDown = coroutine function countDown(x)
85     {
86         yield()
87
88         while(x > 0)
89         {
90             yield(x)
91             x--
92         }
93     }
94
95     foreach(v; countDown, 5)
96         writefln(v)
97
98     writefln()
99
100     local forEach = coroutine function forEach(t)
101     {
102         yield()
103
104         foreach(k, v; t)
105             yield(k, v)
106     }
107     
108     foreach(_, k, v; forEach, {hi = 1, bye = 2})
109         writefln("key: ", k, ", value: ", v)
110
111     writefln()
112 }
113
114 // Testing tailcalls.
115 {
116     local function recurse(x)
117     {
118         writefln("recurse: ", x)
119     
120         if(x == 0)
121             return toString(x)
122         else
123             return recurse(x - 1)
124     }
125
126     writefln(recurse(5))
127     writefln()
128
129     local class A
130     {
131         function f(x)
132         {
133             writefln("A.f: ", x)
134
135             if(x == 0)
136                 return toString(x)
137             else
138                 return :f(x - 1)
139         }
140     }
141
142     writefln(A.f(5))
143     writefln()
144 }
145
146 {
147     // A function which lets us define properties for an object.
148     // The varargs should be a bunch of tables, each with a 'name' field, and 'getter' and/or 'setter' fields.
149     local function mixinProperties(T, vararg)
150     {
151         T._props = { }
152     
153         T.opField = function opField(key)
154         {
155             local prop = :_props[key]
156
157             if(prop is null)
158                 throw format("Property '{}' does not exist in {r}", key, T)
159
160             local getter = prop.getter
161
162             if(getter is null)
163                 throw format("Property '{}' has no getter in {r}", key, T)
164
165             return getter(with this)
166         }
167
168         T.opFieldAssign = function opFieldAssign(key, value)
169         {
170             local prop = :_props[key]
171
172             if(prop is null)
173                 throw format("Property '{}' does not exist in {r}", key, T)
174
175             local setter = prop.setter
176
177             if(setter is null)
178                 throw format("Property '{}' has no setter in {r}", key, T)
179
180             setter(with this, value)
181         }
182     
183         foreach(i, prop; [vararg])
184         {
185             if(!isTable(prop))
186                 throw format("Property ", i, " is not a table")
187
188             if(prop.name is null)
189                 throw format("Property ", i, " has no name")
190
191             if(prop.setter is null && prop.getter is null)
192                 throw format("Property '{}' has no getter or setter", prop.name)
193     
194             T._props[prop.name] = prop
195         }
196     }
197     
198     // Create an object to test out.
199     local class PropTest
200     {
201         mX = 0
202         mY = 0
203         mName = ""
204
205         this(name) :mName = name
206         function toString() = format("name = '", :mName, "' x = ", :mX, " y = ", :mY)
207     }
208
209     // Mix in the properties.
210     mixinProperties(
211         PropTest,
212
213         {
214             name = "x",
215             function setter(value) :mX = value
216             function getter() = :mX
217         },
218
219         {
220             name = "y",
221             function setter(value) :mY = value
222             function getter() = :mY
223         },
224
225         {
226             name = "name",
227             function getter() = :mName
228         }
229     )
230     
231     // Create an instance and try it out.
232     local p = PropTest("hello")
233     
234     writefln(p)
235     p.x = 46
236     p.y = 123
237     p.x = p.x + p.y
238     writefln(p)
239     
240     // Try to access a nonexistent property.
241     try
242         p.name = "crap"
243     catch(e)
244         writefln("caught: ", e)
245
246     writefln()
247 }
248
249 // Some containers.
250 {
251     local class PQ
252     {
253         mData
254         mLength = 0
255
256         this() :mData = array.new(15)
257
258         function insert(data)
259         {
260             :resizeArray()
261             :mData[:mLength] = data
262
263             local index = :mLength
264             local parentIndex = (index - 1) / 2
265
266             while(index > 0 && :mData[parentIndex] > :mData[index])
267             {
268                 local temp = :mData[parentIndex]
269                 :mData[parentIndex] = :mData[index]
270                 :mData[index] = temp
271
272                 index = parentIndex
273                 parentIndex = (index - 1) / 2
274             }
275
276             :mLength += 1
277         }
278
279         function remove()
280         {
281             if(:mLength == 0)
282                 throw "PQ.remove() - No items to remove"
283
284             local data = :mData[0]
285             :mLength -= 1
286             :mData[0] = :mData[:mLength]
287
288             local index = 0
289             local left = 1
290             local right = 2
291     
292             while(index < :mLength)
293             {
294                 local smaller
295
296                 if(left >= :mLength)
297                 {
298                     if(right >= :mLength)
299                         break
300                     else
301                         smaller = right
302                 }
303                 else
304                 {
305                     if(right >= :mLength)
306                         smaller = left
307                     else
308                     {
309                         if(:mData[left] < :mData[right])
310                             smaller = left
311                         else
312                             smaller = right
313                     }
314                 }
315
316                 if(:mData[index] > :mData[smaller])
317                 {
318                     local temp = :mData[index]
319                     :mData[index] = :mData[smaller]
320                     :mData[smaller] = temp
321
322                     index = smaller
323                     left = (index * 2) + 1
324                     right = left + 1
325                 }
326                 else
327                     break
328             }
329
330             return data
331         }
332
333         function resizeArray()
334             if(:mLength >= #:mData)
335                 #:mData = (#:mData + 1) * 2 - 1
336
337         function hasData() = :mLength != 0
338     }
339
340     local class Stack
341     {
342         mHead = null
343
344         function push(data)
345             :mHead = { data = data, next = :mHead }
346
347         function pop()
348         {
349             if(:mHead is null)
350                 throw "Stack.pop() - No items to pop"
351
352             local item = :mHead
353             :mHead = :mHead.next
354
355             return item.data
356         }
357
358         function hasData() = :mHead !is null
359     }
360
361     local class Queue
362     {
363         mHead = null
364         mTail = null
365
366         function push(data)
367         {
368             local t = { data = data, next = null }
369
370             if(:mTail is null)
371                 :mHead = t
372             else
373                 :mTail.next = t
374                 
375             :mTail = t
376         }
377
378         function pop()
379         {
380             if(:mTail is null)
381                 throw "Queue.pop() - No items to pop"
382
383             local item = :mHead
384             :mHead = :mHead.next
385
386             if(:mHead is null)
387                 :mTail = null
388
389             return item.data
390         }
391
392         function hasData() = :mHead !is null
393     }
394
395     writefln("Priority queue (heap)")
396
397     local prioQ = PQ()
398
399     for(i : 0 .. 10)
400         prioQ.insert(math.rand(0, 20))
401
402     while(prioQ.hasData())
403         writefln(prioQ.remove())
404
405     writefln()
406     writefln("Stack")
407
408     local stack = Stack()
409
410     for(i : 0 .. 5)
411         stack.push(i + 1)
412
413     while(stack.hasData())
414         writefln(stack.pop())
415
416     writefln()
417     writefln("Queue")
418
419     local queue = Queue()
420     
421     for(i : 0 .. 5)
422         queue.push(i + 1)
423     
424     while(queue.hasData())
425         writefln(queue.pop())
426     
427     writefln()
428 }
429
430 // opApply tests.
431 {
432     local class Test
433     {
434         mData = [4, 5, 6]
435
436         this() :mData = :mData.dup()
437
438         function opApply(extra)
439         {
440             if(isString(extra) && extra == "reverse")
441             {
442                 local function iterator_reverse(index)
443                 {
444                     index--
445
446                     if(index < 0)
447                         return;
448
449                     return index, :mData[index]
450                 }
451
452                 return iterator_reverse, this, #:mData
453             }
454             else
455             {
456                 local function iterator(index)
457                 {
458                     index++
459
460                     if(index >= #:mData)
461                         return;
462
463                     return index, :mData[index]
464                 }
465
466                 return iterator, this, -1
467             }
468         }
469     }
470     
471     local test = Test()
472     
473     foreach(k, v; test)
474         writefln("test[", k, "] = ", v)
475
476     writefln()
477
478     foreach(k, v; test, "reverse")
479         writefln("test[", k, "] = ", v)
480
481     writefln()
482     
483     test =
484     {
485         fork = 5,
486         knife = 10,
487         spoon = "hi"
488     }
489     
490     foreach(k, v; test)
491         writefln("test[", k, "] = ", v)
492     
493     test = [5, 10, "hi"]
494     
495     writefln()
496     
497     foreach(k, v; test)
498         writefln("test[", k, "] = ", v)
499     
500     writefln()
501     
502     foreach(k, v; test, "reverse")
503         writefln("test[", k, "] = ", v)
504     
505     writefln()
506     
507     foreach(k, v; "hello")
508         writefln("str[", k, "] = ", v)
509
510     writefln()
511
512     foreach(k, v; "hello", "reverse")
513         writefln("str[", k, "] = ", v)
514     
515     writefln()
516 }
517
518 // Testing upvalues in for loops.
519 {
520     local arr = array.new(10)
521     
522     for(i : 0 .. 10)
523         arr[i] = function() = i
524
525     writefln("This should be the values 0 through 9:")
526     
527     foreach(func; arr)
528         writefln(func())
529     
530     writefln()
531 }
532
533 // Testing nested functions.
534 {
535     local function outer()
536     {
537         local x = 3
538
539         function inner()
540         {
541             x++
542             writefln("inner x: ", x)
543         }
544     
545         writefln("outer x: ", x)
546         inner()
547         writefln("outer x: ", x)
548     
549         return inner
550     }
551     
552     local func = outer()
553     func()
554     
555     writefln()
556 }
557
558 // Testing Exceptions.
559 {
560     local function thrower(x)
561         if(x >= 3)
562             throw "Sorry, x is too big for me!"
563
564     local function tryCatch(iterations)
565     {
566         try
567         {
568             for(i : 0 .. iterations)
569             {
570                 writefln("tryCatch: ", i)
571                 thrower(i)
572             }
573         }
574         catch(e)
575         {
576             writefln("tryCatch caught: ", e)
577             throw e
578         }
579         finally
580             writefln("tryCatch finally")
581     }
582     
583     try
584     {
585         tryCatch(2)
586         tryCatch(5)
587     }
588     catch(e)
589         writefln("caught: ", e)
590
591     writefln()
592 }
593
594 // Testing arrays.
595 {
596     local array = [7, 9, 2, 3, 6]
597     
598     array.sort()
599
600     foreach(i, v; array)
601         writefln("arr[", i, "] = ", v)
602
603     array ~= ["foo", "far"]
604     
605     writefln()
606     
607     foreach(i, v; array)
608         writefln("arr[", i, "] = ", v)
609
610     writefln()
611 }
612
613 // Testing vararg functions.
614 {
615     function vargs(vararg)
616     {
617         local args = [vararg]
618     
619         writefln("num varargs: ", #vararg)
620
621         for(i: 0 .. #vararg)
622             writefln("args[", i, "] = ", vararg[i])
623     }
624
625     vargs()
626     writefln()
627     vargs(2, 3, 5, "foo", "bar")
628     writefln()
629 }
630
631 // Testing switches.
632 {
633     foreach(v; ["hi", "bye", "foo"])
634     {
635         switch(v)
636         {
637             case "hi":
638                 writefln("switched to hi")
639                 break
640                 
641             case "bye":
642                 writefln("switched to bye")
643                 break
644                 
645             default:
646                 writefln("switched to something else")
647                 break
648         }
649     }
650     
651     writefln()
652
653     foreach(v; [null, false, 1, 2.3, 'x', "hi"])
654     {
655         switch(v)
656         {
657             case null: writefln("null"); break
658             case false: writefln("false"); break
659             case 1: writefln("1"); break
660             case 2.3: writefln("2.3"); break
661             case 'x': writefln("x"); break
662             case "hi": writefln("hi"); break
663         }
664     }
665     
666     writefln()
667
668     local class A
669     {
670         mValue
671
672         this(value)
673             :mValue = value
674
675         function opCmp(other: A) =
676             :mValue <=> other.mValue
677     }
678
679     local a1 = A(1)
680     local a2 = A(2)
681     local a3 = A(3)
682
683     for(s: 1 .. 4)
684     {
685         local ss = A(s)
686
687         switch(ss)
688         {
689             case a1:
690                 writefln(1)
691                 break
692
693             case a2:
694                 writefln(2)
695                 break
696
697             case a3:
698                 writefln(3)
699                 break
700         }
701     }
702 }+/
Note: See TracBrowser for help on using the browser.