PageRenderTime 84ms CodeModel.GetById 29ms app.highlight 11ms RepoModel.GetById 31ms app.codeStats 0ms

/source/Types.ooc

http://github.com/fperrad/ooc-lua
Unknown | 728 lines | 601 code | 127 blank | 0 comment | 0 complexity | 4c0b24c635cb770a24998e7a6360ca87 MD5 | raw file
  1
  2import io/Writer
  3import math
  4import structs/ArrayList
  5
  6import Opcodes
  7
  8
  9LuaAny: abstract class {
 10    toBool: func -> Bool {
 11        return false
 12    }
 13
 14    toInt: func -> Int {
 15        return 0
 16    }
 17
 18    toNum: func -> Double {
 19        return 0.0
 20    }
 21
 22    toPtr: func -> Pointer {
 23        return null
 24    }
 25
 26    toStr: func -> String {
 27        return null
 28    }
 29
 30    hashval: abstract func -> SizeT
 31
 32    type: abstract func -> String
 33
 34    get: func(key: LuaAny) -> LuaAny {
 35        _typeError("index")
 36        return null
 37    }
 38
 39    set: func(key, val: LuaAny) {
 40        _typeError("index")
 41    }
 42
 43    getMetatable: func -> LuaTable {
 44        return null
 45    }
 46
 47    setMetatable: func(mt: LuaTable) {
 48    }
 49
 50    add: func(op: LuaAny) -> LuaAny {
 51        return _arithError(op)
 52    }
 53
 54    sub: func(op: LuaAny) -> LuaAny {
 55        return _arithError(op)
 56    }
 57
 58    mul: func(op: LuaAny) -> LuaAny {
 59        return _arithError(op)
 60    }
 61
 62    div: func(op: LuaAny) -> LuaAny {
 63        return _arithError(op)
 64    }
 65
 66    mod: func(op: LuaAny) -> LuaAny {
 67        return _arithError(op)
 68    }
 69
 70    pow: func(op: LuaAny) -> LuaAny {
 71        return _arithError(op)
 72    }
 73
 74    unm: func -> LuaAny {
 75        return _arithError(this)
 76    }
 77
 78    len: func -> LuaAny {
 79        _typeError("get length of")
 80        return null
 81    }
 82
 83    concat: func(op: ArrayList<LuaAny>) -> LuaAny {
 84        return _concatError()
 85    }
 86
 87    eq: func(op: LuaAny) -> Bool {
 88        return false
 89    }
 90
 91    lt: func(op: LuaAny) -> Bool {
 92        return _orderError(op)
 93    }
 94
 95    le: func(op: LuaAny) -> Bool {
 96        return _orderError(op)
 97    }
 98
 99    _arithError: func(op: LuaAny) -> LuaAny {
100        _typeError("perform arithmetic on")
101        return null
102    }
103
104    _concatError: func -> LuaAny {
105        _typeError("concatenate")
106        return null
107    }
108
109    _orderError: func(op: LuaAny) -> Bool {
110        t1 := type()
111        t2 := op type()
112        if (t1 equals?(t2))
113            _msgError("attempt to compare two %s values" format(t1))
114        else
115            _msgError("attempt to compare %s with %s" format(t1, t2))
116        return false
117    }
118
119    _typeError: func(msg: String) {
120        _msgError("attempt to %s %s " format(msg, type()))
121    }
122
123    _msgError: func(msg: String) {
124        Exception new(This, msg) throw()
125    }
126}
127
128LuaBoolean: class extends LuaAny {
129    v: Bool
130
131    init: func(=v) {}
132
133    toBool: func -> Bool {
134        return v
135    }
136
137    hashval: func -> SizeT {
138        return v as SizeT
139    }
140
141    type: func -> String {
142        return "boolean"
143    }
144
145    eq: func(op: LuaAny) -> Bool {
146        if (op class != class)
147            return false
148        return v == op as LuaBoolean v
149    }
150}
151
152LuaNil: class extends LuaAny {
153    init: func {}
154
155    hashval: func -> SizeT {
156        return 0
157    }
158
159    type: func -> String {
160        return "nil"
161    }
162
163    eq: func(op: LuaAny) -> Bool {
164        if (op class != class)
165            return false
166        return true
167    }
168}
169
170LuaNumber: class extends LuaAny {
171    v: Double
172
173    init: func(=v) {}
174
175    init: func~int(i: Int) {
176        v = i
177    }
178
179    toInt: func -> Int {
180        return v as Int
181    }
182
183    toNum: func -> Double {
184        return v
185    }
186
187    toStr: func -> String {
188        buff := CString new(20)
189        n := sprintf(buff, "%.14g", v)
190        return String new(buff, n)
191    }
192
193    hashval: func -> SizeT {
194        return v as SizeT
195    }
196
197    type: func -> String {
198        return "number"
199    }
200
201    add: func(op: LuaAny) -> LuaAny {
202        if (op class != class)
203            return _arithError(op)
204        return LuaNumber new(v + op as LuaNumber v)
205    }
206
207    sub: func(op: LuaAny) -> LuaAny {
208        if (op class != class)
209            return _arithError(op)
210        return LuaNumber new(v - op as LuaNumber v)
211    }
212
213    mul: func(op: LuaAny) -> LuaAny {
214        if (op class != class)
215            return _arithError(op)
216        return LuaNumber new(v * op as LuaNumber v)
217    }
218
219    div: func(op: LuaAny) -> LuaAny {
220        if (op class != class)
221            return _arithError(op)
222        return LuaNumber new(v / op as LuaNumber v)
223    }
224
225    mod: func(op: LuaAny) -> LuaAny {
226        if (op class != class)
227            return _arithError(op)
228        v2 := op as LuaNumber v
229        return LuaNumber new(v - (v / v2) floor() * v2)
230    }
231
232    pow: func(op: LuaAny) -> LuaAny {
233        if (op class != class)
234            return _arithError(op)
235        return LuaNumber new(v pow(op as LuaNumber v))
236    }
237
238    unm: func -> LuaAny {
239        return LuaNumber new(- v)
240    }
241
242    eq: func(op: LuaAny) -> Bool {
243        if (op class != class)
244            return false
245        return v == op as LuaNumber v
246    }
247
248    lt: func(op: LuaAny) -> Bool {
249        if (op class != class)
250            return _orderError(op)
251        return v < op as LuaNumber v
252    }
253
254    le: func(op: LuaAny) -> Bool {
255        if (op class != class)
256            return _orderError(op)
257        return v <= op as LuaNumber v
258    }
259}
260
261LuaString: class extends LuaAny {
262    v: String
263
264    init: func(=v) {}
265
266    toStr: func -> String {
267        return v
268    }
269
270    hashval: func -> SizeT {
271        return v as SizeT // internalized string
272    }
273
274    type: func -> String {
275        return "string"
276    }
277
278
279    len: func -> LuaAny {
280        return LuaNumber new(v length())
281    }
282
283    concat: func(op: ArrayList<LuaAny>) -> LuaAny {
284        str := v
285        for (e in op)
286            match (e class) {
287                case LuaString =>
288                    str += e as LuaString v
289                case LuaNumber =>
290                    str += e toStr()
291                case =>
292                    return e _concatError()
293            }
294        return LuaString new(str)
295    }
296
297    eq: func(op: LuaAny) -> Bool {
298        if (op class != class)
299            return false
300        return v equals?(op as LuaString v)
301    }
302
303    lt: func(op: LuaAny) -> Bool {
304        if (op class != class)
305            return _orderError(op)
306        return strcmp(v, op as LuaString v) < 0
307    }
308
309    le: func(op: LuaAny) -> Bool {
310        if (op class != class)
311            return _orderError(op)
312        return strcmp(v, op as LuaString v) <= 0
313    }
314}
315
316MINPOWER2 := const 4    /* minimum size for "growing" vectors */
317
318Node: cover {
319    key: LuaAny
320    val: LuaAny
321    next: Node*
322}
323
324Table: class {
325    node: Node*
326    firstfree: Node*  /* this position is free; all positions after it are full */
327    size: Int
328
329    init: func(narray, nrec: Int) {
330        setnodevector(narray + nrec)
331    }
332
333    /*
334    ** returns the `main' position of an element in a table (that is, the index
335    ** of its hash value)
336    */
337    mainposition: func(key: LuaAny) -> Node* {
338        h := key hashval()
339        version(debug) {
340            assert((h % size) == (h & (size - 1)))
341        }
342        return node + (h & (size - 1))
343    }
344
345    get: func(key: LuaAny) -> LuaAny {
346        n := mainposition(key)
347        while (n) {
348            p := n@ key
349            if (p != null && key eq(p))
350                return n@ val
351            n = n@ next
352        }
353        return null  /* key not found */
354    }
355
356    next: func(key: LuaAny) -> LuaAny {
357        return null
358    }
359
360    /*
361    ** inserts a key into a hash table; first, check whether key is
362    ** already present; if not, check whether key's main position is free;
363    ** if not, check whether colliding node is in its main position or not;
364    ** if it is not, move colliding node to an empty place and put new key
365    ** in its main position; otherwise (colliding node is in its main position),
366    ** new key goes to an empty position.
367    */
368    set: func(key, val: LuaAny) {
369        mp := mainposition(key)
370
371        /* check whether `key' is somewhere in the chain */
372        n := mp
373        while (n) {
374            /* that's all */
375            p := n@ key
376            if (p != null && key eq(p)) {
377                n@ val = val
378                return
379            }
380            else
381                n = n@ next
382        }
383
384        /* `key' not found; must insert it */
385        /* main position is not free? */
386        if (mp@ key) {
387            othern := mainposition(mp@ key)        /* main position of colliding node */
388
389            /* get a free place */
390            n = firstfree
391
392            /* is colliding node out of its main position? (can only happen if
393               its position is after "firstfree") */
394            if (mp as Pointer > n as Pointer && othern as Pointer != mp as Pointer) {
395                /* yes; move colliding node into free position */
396                while (othern@ next as Pointer != mp as Pointer)
397                    othern = othern@ next  /* find previous */
398
399                /* redo the chain with `n' in place of `mp' */
400                othern@ next = n
401
402                /* copy colliding node into free pos. (mp->next also goes) */
403                n@ = mp@
404
405                /* now `mp' is free */
406                mp@ next = null
407            }
408            /* colliding node is in its own main position */
409            else {
410                /* new node will go into free position */
411                /* chain new position */
412                n@ next  = mp@ next
413                mp@ next = n
414                mp       = n
415            }
416        }
417
418        mp@ key = key
419
420        /* correct `firstfree' */
421        while (true) {
422            /* OK; table still has a free place */
423            if (! firstfree@ key) {
424                mp@ val = val
425                return
426            }
427            else if (firstfree as Pointer == node as Pointer)
428                break  /* cannot decrement from here */
429            else
430                firstfree -= 1
431        }
432
433        /* no more free places */
434        rehash()
435
436        /* `rehash' invalidates this insertion */
437        set(key, val)
438    }
439
440    setnodevector: func(_size: Int) {
441        if (_size < MINPOWER2)
442            _size = MINPOWER2
443        size = _size
444        node = gc_malloc(size * Node size) as Node*
445        /* first free position to be used */
446        firstfree = node + (size - 1)
447    }
448
449    numuse: func -> Int {
450        realuse := 0
451        for (i in 0..size)
452            if (node[i] val)
453                realuse += 1
454        return realuse
455    }
456
457    rehash: func {
458        oldsize := size
459        nold := node
460        nelems := numuse()
461
462        version(debug) {
463            assert(nelems <= oldsize) // "wrong count"
464        }
465
466        /* using more than 3/4? */
467        if (nelems >= oldsize - oldsize / 4)
468            setnodevector(oldsize * 2)
469        /* less than 1/4? */
470        else if (nelems <= oldsize / 4 && oldsize > MINPOWER2)
471            setnodevector(oldsize / 2)
472        else
473            setnodevector(oldsize)
474
475        for (i in 0..oldsize) {
476            old := nold + i
477            if (old@ val)
478                set(old@ key, old@ val)
479        }
480
481        /* free old array */
482        gc_free(nold)
483    }
484}
485
486LuaTable: class extends LuaAny {
487    v: Table
488    mt: LuaTable
489
490    init: func(narray, nrec: Int) {
491        v = Table new(narray, nrec)
492    }
493
494    toPtr: func -> Pointer {
495        return null
496    }
497
498    toStr: func -> String {
499        buff := CString new(20)
500        n := sprintf(buff, "table: %08X", v)
501        return String new(buff, n)
502    }
503
504    hashval: func -> SizeT {
505        return v as SizeT
506    }
507
508    type: func -> String {
509        return "table"
510    }
511
512    len: func -> LuaAny {
513        return LuaNumber new(v numuse())
514    }
515
516    eq: func(op: LuaAny) -> Bool {
517        if (op class != class)
518            return false
519        return v == op as LuaTable v
520    }
521
522    get: func(key: LuaAny) -> LuaAny {
523        val := v get(key)
524        if (val == null)
525            val = LuaNil new()
526        return val
527    }
528
529    set: func(key, val: LuaAny) {
530        if (val instanceOf?(LuaNil))
531            val = null
532        v set(key, val)
533    }
534
535    rawEqual: func(op: LuaAny) -> Bool {
536        if (op class != class)
537            return false
538        return v == op as LuaTable v
539    }
540
541    rawGet: func(key: LuaAny) -> LuaAny {
542        val := v get(key)
543        if (val == null)
544            val = LuaNil new()
545        return val
546    }
547
548    rawSet: func(key, val: LuaAny) {
549        if (val instanceOf?(LuaNil))
550            val = null
551        v set(key, val)
552    }
553
554    getMetatable: func -> LuaTable {
555        return mt
556    }
557
558    setMetatable: func(=mt) {}
559
560    next: func(idx: LuaAny) -> LuaAny {
561        return LuaNil new()
562    }
563}
564
565/*
566** Description of an upvalue for function prototypes
567*/
568UpvalDesc: class {
569    name: String  /* upvalue name (for debug information) */
570    instack: Bool  /* whether it is in stack */
571    idx: UInt8  /* index of upvalue (in stack or in outer function's list) */
572
573    init: func(=name, =instack, =idx) {}
574}
575
576
577/*
578** Description of a local variable for function prototypes
579** (used for debug information)
580*/
581LocVar: class {
582    varname: String
583    startpc: Int  /* first point where variable is active */
584    endpc: Int    /* first point where variable is dead */
585
586    init: func(=varname) {}
587}
588
589
590LuaProto: class extends LuaAny {
591    k: ArrayList<LuaAny>  /* constants used by the function */
592    code: ArrayList<Instruction> //~ Instruction *code;
593    p: ArrayList<LuaProto>  /* functions defined inside the function */
594    lineinfo: ArrayList<Int>  /* map from opcodes to source lines */
595    locvars: ArrayList<LocVar>  /* information about local variables */
596    upvalues: ArrayList<UpvalDesc>  /* upvalue information */
597    source: String
598    linedefined: Int
599    lastlinedefined: Int
600    numparams: UInt8;  /* number of fixed parameters */
601    is_vararg: Bool
602    maxstacksize: UInt8  /* maximum stack used by this function */
603
604    init: func {
605        k = ArrayList<LuaAny> new()
606        code = ArrayList<Instruction> new()
607        p = ArrayList<LuaProto> new()
608        lineinfo = ArrayList<Int> new()
609        locvars = ArrayList<LocVar> new()
610        upvalues = ArrayList<UpvalDesc> new()
611    }
612
613    hashval: func -> SizeT {
614        return 0 //
615    }
616
617    type: func -> String {
618        return "proto"
619    }
620
621    _header: func -> ArrayList<Char> {
622        i := 1 as Int
623        h := ArrayList<Char> new(18)
624        h add(0x1b as Char)
625        h add('L')
626        h add('u')
627        h add('a')
628        h add(0x52 as Char)     /* Lua 5.2 */
629        h add(0 as Char)        /* the official format */
630        h add((i& as Char*)@ as Char)   /* endianness */
631        h add(Int size as Char)
632        h add(SizeT size as Char)
633        h add(Instruction size as Char)
634        h add(Double size as Char)
635        h add(0 as Char)        /* is lua_Number integral? */
636        h add(0x19 as Char)
637        h add(0x93 as Char)
638        h add('\r')
639        h add('\n')
640        h add(0x1a as Char)
641        h add('\n')
642        return h
643    }
644
645    dumpHeader: func(w: Writer) {
646        h := _header()
647        w write(h data as Char*, h getSize())
648    }
649
650    dump: func(w: Writer, strip: Bool) {
651        w write(linedefined& as Char*, Int size)
652        w write(lastlinedefined& as Char*, Int size)
653        w write(numparams as Char)
654        w write(is_vararg as Char)
655        w write(maxstacksize as Char)
656        n := code getSize()
657        w write(n& as Char*, Int size)
658        w write(code data as Char*, n * Instruction size)
659        n = k getSize()
660        w write(n& as Char*, Int size)
661        for (i in 0 .. n) {
662            cst := k get(i)
663            match (cst class) {
664                case LuaNil =>
665                    w write(0 as Char)
666                case LuaBoolean =>
667                    w write(1 as Char)
668                    w write(cst as LuaBoolean v as Char)
669                case LuaNumber =>
670                    w write(3 as Char)
671                    num := cst as LuaNumber v
672                    w write(num& as Char*, Double size)
673                case LuaString =>
674                    w write(4 as Char)
675                    str := cst as LuaString v
676                    _dumpString(w, str)
677            }
678        }
679        n = p getSize()
680        w write(n& as Char*, Int size)
681        for (i in 0 .. n)
682            p get(i) dump(w, strip)
683        n = upvalues getSize()
684        w write(n& as Char*, Int size)
685        for (i in 0 .. n) {
686            upv := upvalues get(i)
687            w write(upv instack as Char)
688            w write(upv idx as Char)
689        }
690        if (strip) {
691            n = 0
692            w write(n& as Char*, Int size) // source
693            w write(n& as Char*, Int size) // lineinfo
694            w write(n& as Char*, Int size) // locvars
695            w write(n& as Char*, Int size) // upvalues
696        }
697        else {
698            _dumpString(w, source)
699            n = lineinfo getSize()
700            w write(n& as Char*, Int size)
701            w write(lineinfo data as Char*, n * Int size)
702            n = locvars getSize()
703            w write(n& as Char*, Int size)
704            for (i in 0 .. n) {
705                var := locvars get(i)
706                _dumpString(w, var varname)
707                pc := var startpc
708                w write(pc& as Char*, Int size)
709                pc = var endpc
710                w write(pc& as Char*, Int size)
711            }
712            n = upvalues getSize()
713            w write(n& as Char*, Int size)
714            for (i in 0 .. n)
715                _dumpString(w, upvalues get(i) name)
716        }
717    }
718
719    _dumpString: func(w: Writer, str: String) {
720        len := str length()
721        len1 := len + 1
722        w write(len1& as Char*, Int size)
723        if (len != 0)
724            w write(str, len)
725        w write(0 as Char)
726    }
727}
728