all repos — min @ vm

A small but practical concatenative programming language.

minpkg/core/vm.nim

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
import
    strutils,
    sequtils,
    logging

import
    meta,
    baseutils,
    parser,
    interpreter,
    opcodes

proc toHex*(code: seq[byte]): string =
    code.mapIt(it.toHex).join()

proc bytecode(s: string, symbol = false): seq[byte] =
    result = newSeq[byte](0)
    if symbol:
        result.add opSym.byte
    else:
        result.add opStr.byte
    for c in s:
        result.add c.ord.byte
    result.add opUndef.byte
    var t = "string"
    if symbol:
        t = "symbol"
    logging.debug("$# {$#} $#" % [t, s, result.toHex])

when cpuEndian == littleEndian:
    proc bytecode(n: BiggestInt): seq[byte] =
        result = newSeq[byte](0)
        result.add opPushIn.byte
        result = result.concat(cast[array[0..7, byte]](n).toSeq)
        logging.debug("integer {$#} $#" % [$n, result.toHex])

    proc bytecode(n: BiggestFloat): seq[byte] =
        result = newSeq[byte](0)
        result.add opPushFl.byte
        result = result.concat(cast[array[0..7, byte]](n).toSeq)
        logging.debug("float {$#} $#" % [$n, result.toHex])
else:
    import algorithm

    proc bytecode(n: BiggestInt): seq[byte] =
        result = newSeq[byte](0)
        result.add opPushIn.byte
        result = result.concat(cast[array[0..7, byte]](n).toSeq)
        result.reverse()
        logging.debug("integer {$#} $#" % [$n, result.toHex])

    proc bytecode(n: BiggestFloat): seq[byte] =
        result = newSeq[byte](0)
        result.add opPushFl.byte
        result = result.concat(cast[array[0..7, byte]](n).toSeq)
        result.reverse()
        logging.debug("float {$#} $#" % [$n, result.toHex])

proc generateBytecodeForToken*(p: var MinParser): seq[byte] =
    case p.token:
    of tkNull:
        result.add opPushNl.byte
        discard p.getToken()
        logging.debug("null: ", opPushFa.byte.toHex)
    of tkTrue:
        result.add opPushTr.byte
        discard p.getToken()
        logging.debug("true: ", opPushFa.byte.toHex)
    of tkFalse:
        result.add opPushFa.byte
        discard p.getToken()
        logging.debug("false: ", opPushFa.byte.toHex)
    of tkInt:
        result = result.concat(p.a.parseInt.bytecode)
        p.a = ""
        discard p.getToken()
    of tkFloat:
        result = result.concat(p.a.parseFloat.bytecode)
        p.a = ""
        discard p.getToken()
    of tkString:
        result = result.concat(p.a.escapeEx.bytecode)
        p.a = ""
        discard p.getToken()
    of tkSymbol:
        result = result.concat(p.a.escapeEx.bytecode(true))
        p.a = ""
        discard p.getToken()
    else:
        raiseUndefined(p, "Undefined value: '"&p.a&"'")

proc rawBytecodeCompile*(i: In, indent = ""): seq[byte] {.discardable.} =
    result.add opHead.byte
    for c in pkgName:
        result.add c.ord.byte
    let v = pkgVersion.split(".")
    result.add v[0].parseInt.byte
    result.add v[1].parseInt.byte
    result.add v[2].parseInt.byte
    result.add opUndef.byte
    result.add opUndef.byte
    logging.debug("header: ", result.toHex)
    discard i.parser.getToken()
    while i.parser.token != tkEof:
        if i.trace.len == 0:
            i.stackcopy = i.stack
        result = result.concat(i.parser.generateBytecodeForToken())