| 1 | /*============================================================================ |
|---|
| 2 | ORCA Interpreter |
|---|
| 3 | Copyright (C) 2005-2006 Karl Robillard |
|---|
| 4 | |
|---|
| 5 | This library is free software; you can redistribute it and/or |
|---|
| 6 | modify it under the terms of the GNU Lesser General Public |
|---|
| 7 | License as published by the Free Software Foundation; either |
|---|
| 8 | version 2.1 of the License, or (at your option) any later version. |
|---|
| 9 | |
|---|
| 10 | This library is distributed in the hope that it will be useful, |
|---|
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 13 | Lesser General Public License for more details. |
|---|
| 14 | |
|---|
| 15 | You should have received a copy of the GNU Lesser General Public |
|---|
| 16 | License along with this library; if not, write to the Free Software |
|---|
| 17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 18 | ===========================================================================*/ |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | #include "ovalue.h" |
|---|
| 22 | #include "os.h" |
|---|
| 23 | |
|---|
| 24 | |
|---|
| 25 | /* |
|---|
| 26 | TODO: |
|---|
| 27 | * Save formatting (OR_FLAG_EOL / OR_FLAG_BEOL)? |
|---|
| 28 | * Make word/string table (would make boot.r much smaller)? |
|---|
| 29 | */ |
|---|
| 30 | |
|---|
| 31 | |
|---|
| 32 | #ifdef OR_CONFIG_BYTECODE |
|---|
| 33 | |
|---|
| 34 | #define BIG_VALUE 0x80 |
|---|
| 35 | |
|---|
| 36 | #define RESERVE(n) \ |
|---|
| 37 | orArrayReserve( bin, 1, bin->used + n ); \ |
|---|
| 38 | cp = bin->byteArray + bin->used; \ |
|---|
| 39 | bin->used += n |
|---|
| 40 | |
|---|
| 41 | |
|---|
| 42 | /* |
|---|
| 43 | Appends byte-code representation of value to binary. |
|---|
| 44 | */ |
|---|
| 45 | void orCompileByteCodes( OBinary* bin, const OValue* val ) |
|---|
| 46 | { |
|---|
| 47 | uint8_t* cp; |
|---|
| 48 | |
|---|
| 49 | switch( val->type ) |
|---|
| 50 | { |
|---|
| 51 | case OT_WORD: |
|---|
| 52 | case OT_LITWORD: |
|---|
| 53 | case OT_SETWORD: |
|---|
| 54 | case OT_GETWORD: |
|---|
| 55 | case OT_REFINEMENT: |
|---|
| 56 | { |
|---|
| 57 | int pos; |
|---|
| 58 | int atom; |
|---|
| 59 | |
|---|
| 60 | atom = (val->type == OT_REFINEMENT) ? val->index : val->word.atom; |
|---|
| 61 | pos = bin->used; |
|---|
| 62 | |
|---|
| 63 | orArrayReserve( bin, 1, bin->used + 2 ); |
|---|
| 64 | bin->used += 2; |
|---|
| 65 | |
|---|
| 66 | orAtomStr( atom, bin ); |
|---|
| 67 | |
|---|
| 68 | // LIMIT: Word names can never be more than 255 characters. |
|---|
| 69 | cp = bin->byteArray + pos; |
|---|
| 70 | *cp++ = val->type; |
|---|
| 71 | *cp = bin->used - pos - 2; |
|---|
| 72 | } |
|---|
| 73 | break; |
|---|
| 74 | |
|---|
| 75 | case OT_INTEGER: |
|---|
| 76 | { |
|---|
| 77 | int i = orInt(val); |
|---|
| 78 | if( i > 255 ) |
|---|
| 79 | { |
|---|
| 80 | RESERVE( 5 ); |
|---|
| 81 | *cp++ = BIG_VALUE | val->type; |
|---|
| 82 | *cp++ = (i >> 24) & 0xff; |
|---|
| 83 | *cp++ = (i >> 16) & 0xff; |
|---|
| 84 | *cp++ = (i >> 8) & 0xff; |
|---|
| 85 | } |
|---|
| 86 | else |
|---|
| 87 | { |
|---|
| 88 | RESERVE( 2 ); |
|---|
| 89 | *cp++ = val->type; |
|---|
| 90 | } |
|---|
| 91 | *cp = i & 0xff; |
|---|
| 92 | } |
|---|
| 93 | break; |
|---|
| 94 | |
|---|
| 95 | case OT_DECIMAL: |
|---|
| 96 | { |
|---|
| 97 | const uint8_t* end; |
|---|
| 98 | uint64_t li; |
|---|
| 99 | int shift = 56; |
|---|
| 100 | |
|---|
| 101 | RESERVE( 9 ); |
|---|
| 102 | *cp++ = val->type; |
|---|
| 103 | |
|---|
| 104 | end = cp + 8; |
|---|
| 105 | li = *((uint64_t*) &orDecimal(val)); |
|---|
| 106 | while( cp != end ) |
|---|
| 107 | { |
|---|
| 108 | *cp++ = (uint8_t) (li >> shift) & 0xff; |
|---|
| 109 | shift -= 8; |
|---|
| 110 | } |
|---|
| 111 | } |
|---|
| 112 | break; |
|---|
| 113 | |
|---|
| 114 | case OT_CHAR: |
|---|
| 115 | case OT_LOGIC: |
|---|
| 116 | case OT_DATATYPE: |
|---|
| 117 | RESERVE( 2 ); |
|---|
| 118 | *cp++ = val->type; |
|---|
| 119 | *cp = orInt(val) & 0xff; |
|---|
| 120 | break; |
|---|
| 121 | |
|---|
| 122 | case OT_TUPLE: |
|---|
| 123 | { |
|---|
| 124 | int len = val->argc + 2; |
|---|
| 125 | RESERVE( len ); |
|---|
| 126 | len -= 2; |
|---|
| 127 | *cp++ = val->type; |
|---|
| 128 | *cp++ = len; |
|---|
| 129 | if( len ) |
|---|
| 130 | memCpy( cp, val->tuple, len ); |
|---|
| 131 | } |
|---|
| 132 | break; |
|---|
| 133 | |
|---|
| 134 | //case OT_TIME: |
|---|
| 135 | |
|---|
| 136 | case OT_BLOCK: |
|---|
| 137 | case OT_PAREN: |
|---|
| 138 | case OT_PATH: |
|---|
| 139 | case OT_LITPATH: |
|---|
| 140 | case OT_SETPATH: |
|---|
| 141 | { |
|---|
| 142 | OBlock* blk = orBLOCKS + val->index; |
|---|
| 143 | OValue* it = blk->values + val->series.it; |
|---|
| 144 | OValue* end = blk->values + blk->used; |
|---|
| 145 | int len = end - it; |
|---|
| 146 | |
|---|
| 147 | if( len > 255 ) |
|---|
| 148 | { |
|---|
| 149 | RESERVE( 5 ); |
|---|
| 150 | *cp++ = BIG_VALUE | val->type; |
|---|
| 151 | *cp++ = (len >> 24) & 0xff; |
|---|
| 152 | *cp++ = (len >> 16) & 0xff; |
|---|
| 153 | *cp++ = (len >> 8) & 0xff; |
|---|
| 154 | } |
|---|
| 155 | else |
|---|
| 156 | { |
|---|
| 157 | RESERVE( 2 ); |
|---|
| 158 | *cp++ = val->type; |
|---|
| 159 | } |
|---|
| 160 | *cp = len & 0xff; |
|---|
| 161 | |
|---|
| 162 | while( it != end ) |
|---|
| 163 | { |
|---|
| 164 | orCompileByteCodes( bin, it ); |
|---|
| 165 | ++it; |
|---|
| 166 | } |
|---|
| 167 | } |
|---|
| 168 | break; |
|---|
| 169 | |
|---|
| 170 | case OT_STRING: |
|---|
| 171 | case OT_ISSUE: |
|---|
| 172 | case OT_TAG: |
|---|
| 173 | case OT_FILE: |
|---|
| 174 | case OT_BINARY: |
|---|
| 175 | { |
|---|
| 176 | OString* str = orSTRINGS + val->index; |
|---|
| 177 | int len = str->used - val->series.it; |
|---|
| 178 | |
|---|
| 179 | if( len > 255 ) |
|---|
| 180 | { |
|---|
| 181 | len += 5; |
|---|
| 182 | RESERVE( len ); |
|---|
| 183 | len -= 5; |
|---|
| 184 | *cp++ = BIG_VALUE | val->type; |
|---|
| 185 | *cp++ = (len >> 24) & 0xff; |
|---|
| 186 | *cp++ = (len >> 16) & 0xff; |
|---|
| 187 | *cp++ = (len >> 8) & 0xff; |
|---|
| 188 | } |
|---|
| 189 | else |
|---|
| 190 | { |
|---|
| 191 | len += 2; |
|---|
| 192 | RESERVE( len ); |
|---|
| 193 | len -= 2; |
|---|
| 194 | *cp++ = val->type; |
|---|
| 195 | } |
|---|
| 196 | *cp++ = len & 0xff; |
|---|
| 197 | |
|---|
| 198 | memCpy( cp, str->charArray + val->series.it, len ); |
|---|
| 199 | } |
|---|
| 200 | break; |
|---|
| 201 | |
|---|
| 202 | default: |
|---|
| 203 | RESERVE( 1 ); |
|---|
| 204 | *cp = val->type; |
|---|
| 205 | break; |
|---|
| 206 | } |
|---|
| 207 | } |
|---|
| 208 | |
|---|
| 209 | |
|---|
| 210 | /* |
|---|
| 211 | Returns value length of block. |
|---|
| 212 | Sets lenp to value length and codep to start of value byte-code. |
|---|
| 213 | */ |
|---|
| 214 | OIndex orByteCodeBlock( const uint8_t** codep, OIndex* lenp ) |
|---|
| 215 | { |
|---|
| 216 | int type; |
|---|
| 217 | int big; |
|---|
| 218 | OIndex len = 0; |
|---|
| 219 | const uint8_t* cp = *codep; |
|---|
| 220 | |
|---|
| 221 | type = *cp++; |
|---|
| 222 | big = type & BIG_VALUE; |
|---|
| 223 | if( big ) |
|---|
| 224 | type &= ~BIG_VALUE; |
|---|
| 225 | |
|---|
| 226 | if( type == OT_BLOCK ) |
|---|
| 227 | { |
|---|
| 228 | if( big ) |
|---|
| 229 | { |
|---|
| 230 | len = *cp++ << 24; |
|---|
| 231 | len += *cp++ << 16; |
|---|
| 232 | len += *cp++ << 8; |
|---|
| 233 | len += *cp++; |
|---|
| 234 | } |
|---|
| 235 | else |
|---|
| 236 | { |
|---|
| 237 | len = *cp++; |
|---|
| 238 | } |
|---|
| 239 | |
|---|
| 240 | *codep = cp; |
|---|
| 241 | } |
|---|
| 242 | |
|---|
| 243 | *lenp = len; |
|---|
| 244 | return len; |
|---|
| 245 | } |
|---|
| 246 | |
|---|
| 247 | |
|---|
| 248 | /* |
|---|
| 249 | Appends value representation of byte-codes to block. |
|---|
| 250 | */ |
|---|
| 251 | const uint8_t* orRevaluateByteCodes( const uint8_t* cp, int valueCount, |
|---|
| 252 | OBlock* blk ) |
|---|
| 253 | { |
|---|
| 254 | OIndex blkN; |
|---|
| 255 | int type; |
|---|
| 256 | int len; |
|---|
| 257 | int big; |
|---|
| 258 | |
|---|
| 259 | blkN = orBlockN( blk ); |
|---|
| 260 | |
|---|
| 261 | while( valueCount-- ) |
|---|
| 262 | { |
|---|
| 263 | type = *cp++; |
|---|
| 264 | |
|---|
| 265 | big = type & BIG_VALUE; |
|---|
| 266 | if( big ) |
|---|
| 267 | type &= ~BIG_VALUE; |
|---|
| 268 | |
|---|
| 269 | switch( type ) |
|---|
| 270 | { |
|---|
| 271 | case OT_WORD: |
|---|
| 272 | case OT_LITWORD: |
|---|
| 273 | case OT_SETWORD: |
|---|
| 274 | case OT_GETWORD: |
|---|
| 275 | { |
|---|
| 276 | len = *cp++; |
|---|
| 277 | orAppendWord( blk, type, (const char*) cp, len ); |
|---|
| 278 | cp += len; |
|---|
| 279 | } |
|---|
| 280 | break; |
|---|
| 281 | |
|---|
| 282 | case OT_REFINEMENT: |
|---|
| 283 | { |
|---|
| 284 | int n; |
|---|
| 285 | len = *cp++; |
|---|
| 286 | n = orInternAtom( (const char*) cp, len ); |
|---|
| 287 | cp += len; |
|---|
| 288 | orAppendValue( blk, type, n ); |
|---|
| 289 | } |
|---|
| 290 | break; |
|---|
| 291 | |
|---|
| 292 | case OT_INTEGER: |
|---|
| 293 | if( big ) |
|---|
| 294 | { |
|---|
| 295 | len = *cp++ << 24; |
|---|
| 296 | len += *cp++ << 16; |
|---|
| 297 | len += *cp++ << 8; |
|---|
| 298 | len += *cp++; |
|---|
| 299 | } |
|---|
| 300 | else |
|---|
| 301 | { |
|---|
| 302 | len = *cp++; |
|---|
| 303 | } |
|---|
| 304 | orAppendValue( blk, type, len ); |
|---|
| 305 | break; |
|---|
| 306 | |
|---|
| 307 | case OT_DECIMAL: |
|---|
| 308 | { |
|---|
| 309 | const uint8_t* end; |
|---|
| 310 | double n; |
|---|
| 311 | union { |
|---|
| 312 | uint64_t i; |
|---|
| 313 | double d; |
|---|
| 314 | } num; |
|---|
| 315 | |
|---|
| 316 | num.i = *cp++; |
|---|
| 317 | end = cp + 7; |
|---|
| 318 | while( cp != end ) |
|---|
| 319 | { |
|---|
| 320 | num.i <<= 8; |
|---|
| 321 | num.i += *cp++; |
|---|
| 322 | } |
|---|
| 323 | n = num.d; |
|---|
| 324 | orAppendDecimal( blk, n ); |
|---|
| 325 | } |
|---|
| 326 | break; |
|---|
| 327 | |
|---|
| 328 | case OT_CHAR: |
|---|
| 329 | case OT_LOGIC: |
|---|
| 330 | case OT_DATATYPE: |
|---|
| 331 | orAppendValue( blk, type, *cp++ ); |
|---|
| 332 | break; |
|---|
| 333 | |
|---|
| 334 | case OT_TUPLE: |
|---|
| 335 | len = *cp++; |
|---|
| 336 | orAppendTuple( blk, cp, len ); |
|---|
| 337 | cp += len; |
|---|
| 338 | break; |
|---|
| 339 | |
|---|
| 340 | case OT_BLOCK: |
|---|
| 341 | case OT_PAREN: |
|---|
| 342 | case OT_PATH: |
|---|
| 343 | case OT_LITPATH: |
|---|
| 344 | case OT_SETPATH: |
|---|
| 345 | { |
|---|
| 346 | if( big ) |
|---|
| 347 | { |
|---|
| 348 | len = *cp++ << 24; |
|---|
| 349 | len += *cp++ << 16; |
|---|
| 350 | len += *cp++ << 8; |
|---|
| 351 | len += *cp++; |
|---|
| 352 | } |
|---|
| 353 | else |
|---|
| 354 | { |
|---|
| 355 | len = *cp++; |
|---|
| 356 | } |
|---|
| 357 | |
|---|
| 358 | blk = orMakeBlock( len ); |
|---|
| 359 | orAppendValue( orBLOCKS + blkN, type, blk - orBLOCKS ); |
|---|
| 360 | cp = orRevaluateByteCodes( cp, len, blk ); |
|---|
| 361 | |
|---|
| 362 | // Re-acquire blk. |
|---|
| 363 | blk = orBLOCKS + blkN; |
|---|
| 364 | } |
|---|
| 365 | break; |
|---|
| 366 | |
|---|
| 367 | case OT_STRING: |
|---|
| 368 | case OT_ISSUE: |
|---|
| 369 | case OT_TAG: |
|---|
| 370 | case OT_FILE: |
|---|
| 371 | case OT_BINARY: |
|---|
| 372 | if( big ) |
|---|
| 373 | { |
|---|
| 374 | len = *cp++ << 24; |
|---|
| 375 | len += *cp++ << 16; |
|---|
| 376 | len += *cp++ << 8; |
|---|
| 377 | len += *cp++; |
|---|
| 378 | } |
|---|
| 379 | else |
|---|
| 380 | { |
|---|
| 381 | len = *cp++; |
|---|
| 382 | } |
|---|
| 383 | orAppendValue( blk, type, orMakeCString((const char*) cp, len) ); |
|---|
| 384 | cp += len; |
|---|
| 385 | break; |
|---|
| 386 | |
|---|
| 387 | case OT_NONE: |
|---|
| 388 | orAppendNone( blk ); |
|---|
| 389 | break; |
|---|
| 390 | |
|---|
| 391 | default: |
|---|
| 392 | break; |
|---|
| 393 | } |
|---|
| 394 | } |
|---|
| 395 | |
|---|
| 396 | return cp; |
|---|
| 397 | } |
|---|
| 398 | |
|---|
| 399 | #endif |
|---|
| 400 | |
|---|
| 401 | |
|---|
| 402 | /*EOF*/ |
|---|