mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Start using UnaryOp/PostUnaryOp ++/-- now works post/pre and also on pointers. Fix ++/-- on any number. Added examples. c3c now compiles files by default. Extended symbol resolution. Addition of 'extern'. Multi-level paths.
This commit is contained in:
@@ -136,6 +136,9 @@ L?\"(\\.|[^\\"])*\" { count(); return(STRING_LITERAL); }
|
||||
"^" { count(); return('^'); }
|
||||
"|" { count(); return('|'); }
|
||||
"?" { count(); return('?'); }
|
||||
"+%" { count(); return(ADDW); }
|
||||
"*%" { count(); return(MULTW); }
|
||||
"-%" { count(); return(SUBW); }
|
||||
"({" { count(); return(FN_BLOCK_BEGIN); }
|
||||
"{)" { count(); return(FN_BLOCK_END); }
|
||||
[ \t\v\n\f] { count(); }
|
||||
|
||||
121
resources/examples/base64.c3
Normal file
121
resources/examples/base64.c3
Normal file
@@ -0,0 +1,121 @@
|
||||
module base64;
|
||||
// Based on the C2 version.
|
||||
|
||||
const char[] LUT_ENC = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||
'4', '5', '6', '7', '8', '9', '+', '/',
|
||||
};
|
||||
|
||||
const byte ERR = 0xFF;
|
||||
|
||||
const byte[256] LUT_DEC = {
|
||||
// '+', ',', '-', '.', '/', '0', '1', '2'
|
||||
62, ERR, ERR, ERR, 63, 52, 53, 54,
|
||||
// '3', '4', '5', '6', '7', '8', '9', ':'
|
||||
55, 56, 57, 58, 59, 60, 61, ERR,
|
||||
// ';', '<', '=', '>', '?', '@', 'A', 'B'
|
||||
ERR, ERR, ERR, ERR, ERR, ERR, 0, 1,
|
||||
// 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'
|
||||
2, 3, 4, 5, 6, 7, 8, 9,
|
||||
// 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R'
|
||||
10, 11, 12, 13, 14, 15, 16, 17,
|
||||
// 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
|
||||
18, 19, 20, 21, 22, 23, 24, 25,
|
||||
// '[', '\', ']', '^', '_', '`', 'a', 'b'
|
||||
ERR, ERR, ERR, ERR, ERR, ERR, 26, 27,
|
||||
// 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'
|
||||
28, 29, 30, 31, 32, 33, 34, 35,
|
||||
// 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r'
|
||||
36, 37, 38, 39, 40, 41, 42, 43,
|
||||
// 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
|
||||
44, 45, 46, 47, 48, 49, 50, 51,
|
||||
};
|
||||
|
||||
|
||||
const char PAD = '=';
|
||||
const char FIRST = '+';
|
||||
const char LAST = 'z';
|
||||
|
||||
public error Base64Error
|
||||
{
|
||||
INVALID_CHARACTER
|
||||
}
|
||||
|
||||
public func void encode(byte[] in, string *out)
|
||||
{
|
||||
int j = 0;
|
||||
|
||||
for (int i = 0; i < in.len; i++);
|
||||
{
|
||||
switch (i % 3)
|
||||
{
|
||||
case 0:
|
||||
out[j++] = LUT_ENC[(in[i] >> 2) & 0x3F];
|
||||
case 1:
|
||||
out[j++] = LUT_ENC[(in[i-1] & 0x3) << 4 + ((in[i] >> 4) & 0xF)];
|
||||
case 2:
|
||||
out[j++] = LUT_ENC[(in[i-1] & 0xF) << 2 + ((in[i] >> 6) & 0x3)];
|
||||
out[j++] = LUT_ENC[in[i] & 0x3F];
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// move back
|
||||
int last = in.len - 1;
|
||||
|
||||
// check the last and add padding
|
||||
switch (last % 3)
|
||||
{
|
||||
case 0:
|
||||
out[j++] = LUT_ENC[(in[last] & 0x3) << 4];
|
||||
out[j++] = PAD;
|
||||
out[j++] = PAD;
|
||||
case 1:
|
||||
out[j++] = LUT_ENC[(in[last] & 0xF) << 2];
|
||||
out[j++] = PAD;
|
||||
}
|
||||
}
|
||||
|
||||
public func int decode(string in, byte[] out) throws Base64Error
|
||||
{
|
||||
int j = 0;
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
char value = in[i];
|
||||
|
||||
if (value == PAD) return j;
|
||||
|
||||
if (value < FIRST || in[i] > LAST) throw INVALID_CHARACTER;
|
||||
byte c = LUT_DEC[in[i] - FIRST);
|
||||
if (c == ERR) throw INVALID_CHARACTER;
|
||||
|
||||
switch (i % 4)
|
||||
{
|
||||
case 0:
|
||||
out[j] = c << 2;
|
||||
case 1:
|
||||
out[j++] += (c >> 4) & 0x3;
|
||||
// if not last char with padding
|
||||
if (i < (len - 3) || in[len - 2] != PAD)
|
||||
{
|
||||
out[j] = (c & 0xF) << 4;
|
||||
}
|
||||
case 2:
|
||||
out[j++] += (c >> 2) & 0xF;
|
||||
if (i < (len -2) || in[len -1] != PAD)
|
||||
{
|
||||
out[j] = (c & 0x3) << 6;
|
||||
}
|
||||
case 3:
|
||||
out[j++] += c;
|
||||
}
|
||||
}
|
||||
return j;
|
||||
}
|
||||
21
resources/examples/binarydigits.c3
Normal file
21
resources/examples/binarydigits.c3
Normal file
@@ -0,0 +1,21 @@
|
||||
module binarydigits;
|
||||
|
||||
func int main()
|
||||
{
|
||||
fot (int i = 0; i < 20; i++)
|
||||
{
|
||||
printf("%s\n", bin(i));
|
||||
}
|
||||
}
|
||||
|
||||
func string@ bin(int x)
|
||||
{
|
||||
int bits = (x == 0) ? 1 : log10(cast(double, x)) / log10(2);
|
||||
string@ ret = string.make_repeat('0', bits);
|
||||
for (int i = 0; i < bits; i++)
|
||||
{
|
||||
ret[bits - i - 1] = x & 1 ? '1' : '0';
|
||||
x >>= 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
77
resources/examples/gameoflife.c3
Normal file
77
resources/examples/gameoflife.c3
Normal file
@@ -0,0 +1,77 @@
|
||||
module game_of_life;
|
||||
|
||||
struct GameBoard
|
||||
{
|
||||
int h;
|
||||
int w;
|
||||
byte* world;
|
||||
byte* temp;
|
||||
}
|
||||
|
||||
func void GameBoard.show(GameBoard *board)
|
||||
{
|
||||
printf("\033[H");
|
||||
byte* current = board.world;
|
||||
for (int y = 0; y < board.h; y++)
|
||||
{
|
||||
for (int x = 0; x < board.w; x++)
|
||||
{
|
||||
printf(*current ? "\033[07m \033[m" : " ");
|
||||
}
|
||||
printf("\033[E");
|
||||
}
|
||||
stdout.fflush();
|
||||
}
|
||||
|
||||
func void GameBoard.evolve(GameBoard *board)
|
||||
{
|
||||
for (int y = 0; y < board.h; y++)
|
||||
{
|
||||
for (int x = 0; x < board.w; x++)
|
||||
{
|
||||
int n = 0;
|
||||
for (int y1 = y - 1; y1 <= y + 1; y1++)
|
||||
{
|
||||
for (int x1 = x - 1; x1 <= x + 1; x1++)
|
||||
{
|
||||
int actualX = (x1 + w) % w;
|
||||
int actualY = (y1 + h) % h;
|
||||
if (board.world[x + y * w]) n++;
|
||||
}
|
||||
}
|
||||
if (board.world(x + y * w)) n--;
|
||||
board.temp[x + y * w] = (n == 3 || (n == 2 && board.world(x + y * w)));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < w * h; i++)
|
||||
{
|
||||
board.world[i] = board.temp[i];
|
||||
}
|
||||
}
|
||||
|
||||
int main(int c, string[] v)
|
||||
{
|
||||
int w = 0, h = 0;
|
||||
if (c > 1) w = atoi(v[1]);
|
||||
if (c > 2) h = atoi(v[2]);
|
||||
if (w <= 0) w = 30;
|
||||
if (h <= 0) h = 30;
|
||||
|
||||
GameBoard board;
|
||||
board.w = w;
|
||||
board.h = h;
|
||||
board.board = malloc(h * w);
|
||||
board.temp = malloc(h * w);
|
||||
|
||||
for (int i = h * w - 1; i >= 0; i--)
|
||||
{
|
||||
board.world[i] = rand() < RAND_MAX / 10 ? 1 : 0;
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
|
||||
board.show();
|
||||
board.evolve();
|
||||
usleep(200000);
|
||||
}
|
||||
}
|
||||
212
resources/examples/hash.c3
Normal file
212
resources/examples/hash.c3
Normal file
@@ -0,0 +1,212 @@
|
||||
module hash;
|
||||
|
||||
// Code adapted from Odin's hash.odin
|
||||
// The code below should not be considered *correct*
|
||||
// They are merely done to illustrate the language syntax.
|
||||
|
||||
public func uint adler32(byte[] data)
|
||||
{
|
||||
const uint ADLER_CONST = 65521;
|
||||
uint a = 1;
|
||||
uint b = 0;
|
||||
for (byte x : data)
|
||||
{
|
||||
a = (a + x) % ADLER_CONST;
|
||||
b = (b + a) % ADLER_CONST;
|
||||
}
|
||||
return (b << 16) | a;
|
||||
}
|
||||
|
||||
public func uint crc32(byte[] data)
|
||||
{
|
||||
uint result = ~cast(uint, 0);
|
||||
for (byte x : data)
|
||||
{
|
||||
result = (result >> 8) ^ CRC32_TABLE[result ^ x) & 255];
|
||||
}
|
||||
return ~result;
|
||||
}
|
||||
|
||||
public func uint crc64(byte[*] data)
|
||||
{
|
||||
ulong result = ~cast(ulong, 0);
|
||||
for (byte x : data)
|
||||
{
|
||||
result = (result >> 8) ^ CRC64_TABLE[(result ^ x) & 255];
|
||||
}
|
||||
return ~result;
|
||||
}
|
||||
|
||||
public func uint fnv32(byte[*] data)
|
||||
{
|
||||
uint h = 0x811c9dc5;
|
||||
for (byte x : data)
|
||||
{
|
||||
h = (h *% 0x01000193) ^ x;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
public func ulong fnv64(byte[] data)
|
||||
{
|
||||
ulong h = 0xcbf29ce484222325;
|
||||
for (byte x : data)
|
||||
{
|
||||
h = (h *% 0x100000001b3) ^ x;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
public func uint fnv32a(byte[] data)
|
||||
{
|
||||
uint h = 0x811c9dc5;
|
||||
for (byte x : data)
|
||||
{
|
||||
h = (h ^ b) *% 0x01000193;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
public func ulong fnv32a(byte[] data)
|
||||
{
|
||||
ulong h = 0xcbf29ce484222325;
|
||||
for (byte x in data)
|
||||
{
|
||||
h = (h ^ b) *% 0x100000001b3;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
const uint[256] CRC32_TABLE = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
||||
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
||||
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
|
||||
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
|
||||
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
||||
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
||||
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
|
||||
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
|
||||
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
||||
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
||||
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
|
||||
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
|
||||
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
||||
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
||||
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
|
||||
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
|
||||
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
||||
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
||||
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
|
||||
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
|
||||
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
||||
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
||||
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
|
||||
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
|
||||
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
||||
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
||||
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
|
||||
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
|
||||
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
||||
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
||||
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
|
||||
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
|
||||
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
||||
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
||||
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
|
||||
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
|
||||
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
||||
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
||||
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
|
||||
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
|
||||
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
|
||||
};
|
||||
|
||||
const ulong[256] CRC64_TABLE = {
|
||||
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
|
||||
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
|
||||
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
|
||||
0xdb55aacf12c73561, 0x99a54b24bb2d03f2, 0x5eb4691841135847, 0x1c4488f3e8f96ed4,
|
||||
0x663d78ff90e185ef, 0x24cd9914390bb37c, 0xe3dcbb28c335e8c9, 0xa12c5ac36adfde5a,
|
||||
0x2f0e1eba9ea36930, 0x6dfeff5137495fa3, 0xaaefdd6dcd770416, 0xe81f3c86649d3285,
|
||||
0xf45bb4758c645c51, 0xb6ab559e258e6ac2, 0x71ba77a2dfb03177, 0x334a9649765a07e4,
|
||||
0xbd68d2308226b08e, 0xff9833db2bcc861d, 0x388911e7d1f2dda8, 0x7a79f00c7818eb3b,
|
||||
0xcc7af1ff21c30bde, 0x8e8a101488293d4d, 0x499b3228721766f8, 0x0b6bd3c3dbfd506b,
|
||||
0x854997ba2f81e701, 0xc7b97651866bd192, 0x00a8546d7c558a27, 0x4258b586d5bfbcb4,
|
||||
0x5e1c3d753d46d260, 0x1cecdc9e94ace4f3, 0xdbfdfea26e92bf46, 0x990d1f49c77889d5,
|
||||
0x172f5b3033043ebf, 0x55dfbadb9aee082c, 0x92ce98e760d05399, 0xd03e790cc93a650a,
|
||||
0xaa478900b1228e31, 0xe8b768eb18c8b8a2, 0x2fa64ad7e2f6e317, 0x6d56ab3c4b1cd584,
|
||||
0xe374ef45bf6062ee, 0xa1840eae168a547d, 0x66952c92ecb40fc8, 0x2465cd79455e395b,
|
||||
0x3821458aada7578f, 0x7ad1a461044d611c, 0xbdc0865dfe733aa9, 0xff3067b657990c3a,
|
||||
0x711223cfa3e5bb50, 0x33e2c2240a0f8dc3, 0xf4f3e018f031d676, 0xb60301f359dbe0e5,
|
||||
0xda050215ea6c212f, 0x98f5e3fe438617bc, 0x5fe4c1c2b9b84c09, 0x1d14202910527a9a,
|
||||
0x93366450e42ecdf0, 0xd1c685bb4dc4fb63, 0x16d7a787b7faa0d6, 0x5427466c1e109645,
|
||||
0x4863ce9ff6e9f891, 0x0a932f745f03ce02, 0xcd820d48a53d95b7, 0x8f72eca30cd7a324,
|
||||
0x0150a8daf8ab144e, 0x43a04931514122dd, 0x84b16b0dab7f7968, 0xc6418ae602954ffb,
|
||||
0xbc387aea7a8da4c0, 0xfec89b01d3679253, 0x39d9b93d2959c9e6, 0x7b2958d680b3ff75,
|
||||
0xf50b1caf74cf481f, 0xb7fbfd44dd257e8c, 0x70eadf78271b2539, 0x321a3e938ef113aa,
|
||||
0x2e5eb66066087d7e, 0x6cae578bcfe24bed, 0xabbf75b735dc1058, 0xe94f945c9c3626cb,
|
||||
0x676dd025684a91a1, 0x259d31cec1a0a732, 0xe28c13f23b9efc87, 0xa07cf2199274ca14,
|
||||
0x167ff3eacbaf2af1, 0x548f120162451c62, 0x939e303d987b47d7, 0xd16ed1d631917144,
|
||||
0x5f4c95afc5edc62e, 0x1dbc74446c07f0bd, 0xdaad56789639ab08, 0x985db7933fd39d9b,
|
||||
0x84193f60d72af34f, 0xc6e9de8b7ec0c5dc, 0x01f8fcb784fe9e69, 0x43081d5c2d14a8fa,
|
||||
0xcd2a5925d9681f90, 0x8fdab8ce70822903, 0x48cb9af28abc72b6, 0x0a3b7b1923564425,
|
||||
0x70428b155b4eaf1e, 0x32b26afef2a4998d, 0xf5a348c2089ac238, 0xb753a929a170f4ab,
|
||||
0x3971ed50550c43c1, 0x7b810cbbfce67552, 0xbc902e8706d82ee7, 0xfe60cf6caf321874,
|
||||
0xe224479f47cb76a0, 0xa0d4a674ee214033, 0x67c58448141f1b86, 0x253565a3bdf52d15,
|
||||
0xab1721da49899a7f, 0xe9e7c031e063acec, 0x2ef6e20d1a5df759, 0x6c0603e6b3b7c1ca,
|
||||
0xf6fae5c07d3274cd, 0xb40a042bd4d8425e, 0x731b26172ee619eb, 0x31ebc7fc870c2f78,
|
||||
0xbfc9838573709812, 0xfd39626eda9aae81, 0x3a28405220a4f534, 0x78d8a1b9894ec3a7,
|
||||
0x649c294a61b7ad73, 0x266cc8a1c85d9be0, 0xe17dea9d3263c055, 0xa38d0b769b89f6c6,
|
||||
0x2daf4f0f6ff541ac, 0x6f5faee4c61f773f, 0xa84e8cd83c212c8a, 0xeabe6d3395cb1a19,
|
||||
0x90c79d3fedd3f122, 0xd2377cd44439c7b1, 0x15265ee8be079c04, 0x57d6bf0317edaa97,
|
||||
0xd9f4fb7ae3911dfd, 0x9b041a914a7b2b6e, 0x5c1538adb04570db, 0x1ee5d94619af4648,
|
||||
0x02a151b5f156289c, 0x4051b05e58bc1e0f, 0x87409262a28245ba, 0xc5b073890b687329,
|
||||
0x4b9237f0ff14c443, 0x0962d61b56fef2d0, 0xce73f427acc0a965, 0x8c8315cc052a9ff6,
|
||||
0x3a80143f5cf17f13, 0x7870f5d4f51b4980, 0xbf61d7e80f251235, 0xfd913603a6cf24a6,
|
||||
0x73b3727a52b393cc, 0x31439391fb59a55f, 0xf652b1ad0167feea, 0xb4a25046a88dc879,
|
||||
0xa8e6d8b54074a6ad, 0xea16395ee99e903e, 0x2d071b6213a0cb8b, 0x6ff7fa89ba4afd18,
|
||||
0xe1d5bef04e364a72, 0xa3255f1be7dc7ce1, 0x64347d271de22754, 0x26c49cccb40811c7,
|
||||
0x5cbd6cc0cc10fafc, 0x1e4d8d2b65facc6f, 0xd95caf179fc497da, 0x9bac4efc362ea149,
|
||||
0x158e0a85c2521623, 0x577eeb6e6bb820b0, 0x906fc95291867b05, 0xd29f28b9386c4d96,
|
||||
0xcedba04ad0952342, 0x8c2b41a1797f15d1, 0x4b3a639d83414e64, 0x09ca82762aab78f7,
|
||||
0x87e8c60fded7cf9d, 0xc51827e4773df90e, 0x020905d88d03a2bb, 0x40f9e43324e99428,
|
||||
0x2cffe7d5975e55e2, 0x6e0f063e3eb46371, 0xa91e2402c48a38c4, 0xebeec5e96d600e57,
|
||||
0x65cc8190991cb93d, 0x273c607b30f68fae, 0xe02d4247cac8d41b, 0xa2dda3ac6322e288,
|
||||
0xbe992b5f8bdb8c5c, 0xfc69cab42231bacf, 0x3b78e888d80fe17a, 0x7988096371e5d7e9,
|
||||
0xf7aa4d1a85996083, 0xb55aacf12c735610, 0x724b8ecdd64d0da5, 0x30bb6f267fa73b36,
|
||||
0x4ac29f2a07bfd00d, 0x08327ec1ae55e69e, 0xcf235cfd546bbd2b, 0x8dd3bd16fd818bb8,
|
||||
0x03f1f96f09fd3cd2, 0x41011884a0170a41, 0x86103ab85a2951f4, 0xc4e0db53f3c36767,
|
||||
0xd8a453a01b3a09b3, 0x9a54b24bb2d03f20, 0x5d45907748ee6495, 0x1fb5719ce1045206,
|
||||
0x919735e51578e56c, 0xd367d40ebc92d3ff, 0x1476f63246ac884a, 0x568617d9ef46bed9,
|
||||
0xe085162ab69d5e3c, 0xa275f7c11f7768af, 0x6564d5fde549331a, 0x279434164ca30589,
|
||||
0xa9b6706fb8dfb2e3, 0xeb46918411358470, 0x2c57b3b8eb0bdfc5, 0x6ea7525342e1e956,
|
||||
0x72e3daa0aa188782, 0x30133b4b03f2b111, 0xf7021977f9cceaa4, 0xb5f2f89c5026dc37,
|
||||
0x3bd0bce5a45a6b5d, 0x79205d0e0db05dce, 0xbe317f32f78e067b, 0xfcc19ed95e6430e8,
|
||||
0x86b86ed5267cdbd3, 0xc4488f3e8f96ed40, 0x0359ad0275a8b6f5, 0x41a94ce9dc428066,
|
||||
0xcf8b0890283e370c, 0x8d7be97b81d4019f, 0x4a6acb477bea5a2a, 0x089a2aacd2006cb9,
|
||||
0x14dea25f3af9026d, 0x562e43b4931334fe, 0x913f6188692d6f4b, 0xd3cf8063c0c759d8,
|
||||
0x5dedc41a34bbeeb2, 0x1f1d25f19d51d821, 0xd80c07cd676f8394, 0x9afce626ce85b507,
|
||||
};
|
||||
26
resources/examples/http.c3
Normal file
26
resources/examples/http.c3
Normal file
@@ -0,0 +1,26 @@
|
||||
import curl;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
try Curl curl = Curl.new();
|
||||
|
||||
catch (error e)
|
||||
{
|
||||
printf("Failed to create new curl: %s\n", e.message);
|
||||
exit(FAILURE);
|
||||
}
|
||||
|
||||
curl.setopt(URL, "http://www.rosettacode.org/");
|
||||
curl.setopt(FOLLOWLOCATION, 1);
|
||||
|
||||
try curl.perform();
|
||||
|
||||
catch (CurlError e)
|
||||
{
|
||||
printf("Error making request: %s\n", e.message);
|
||||
exit(FAILURE);
|
||||
}
|
||||
|
||||
exit(SUCCESS);
|
||||
|
||||
}
|
||||
24
resources/examples/levenshtein.c3
Normal file
24
resources/examples/levenshtein.c3
Normal file
@@ -0,0 +1,24 @@
|
||||
module levenshtein;
|
||||
|
||||
func int levenshtein(string s, string t)
|
||||
{
|
||||
// if either string is empty, difference is inserting all chars
|
||||
// from the other
|
||||
if (!s.size) return t.size;
|
||||
if (!t.size) return s.size;
|
||||
|
||||
// if last letters are the same, the difference is whatever is
|
||||
// required to edit the rest of the strings
|
||||
if (s[s.size - 1] == t[t.size - 1]) return levenshtein(s.slice(0, s.size - 1), t.slice(0, t.size - 1));
|
||||
|
||||
// else try:
|
||||
// changing last letter of s to that of t; or
|
||||
// remove last letter of s; or
|
||||
// remove last letter of t,
|
||||
// any of which is 1 edit plus editing the rest of the strings
|
||||
int a = levenshtein(s.slice(0, s.size - 1), t.slice(0, t.size - 1));
|
||||
int b = levenshtein(s, t.slice(0, t.size - 1);
|
||||
int c = levenshtein(s.slice(0, s.size - 1), t);
|
||||
|
||||
return @max(@max(a, b), c) + 1;
|
||||
}
|
||||
31
resources/examples/madlibs.c3
Normal file
31
resources/examples/madlibs.c3
Normal file
@@ -0,0 +1,31 @@
|
||||
module madlibs;
|
||||
import regex, stdio;
|
||||
|
||||
func void main()
|
||||
{
|
||||
println("Enter a story template, terminated by an empty line:");
|
||||
string@ story = "";
|
||||
while (1)
|
||||
{
|
||||
try string line = stdin.readln().strip();
|
||||
if (!line.size) break;
|
||||
story += line + "\n";
|
||||
}
|
||||
|
||||
Regex* r = try regex::regexWithOptions("<.+?>", RegexOpt.GLOBAL) catch @unreachable;
|
||||
|
||||
foreach (RegexMatch* match : r.match(story))
|
||||
{
|
||||
string s = match.string;
|
||||
printf("Enter a value for '%s': ", s.slice(1, s.size - 2));
|
||||
try string word = strin.readln().strip();
|
||||
story = story.replace(s, word);
|
||||
}
|
||||
|
||||
println("\nThe story becomes:\n%s\n", story);
|
||||
|
||||
catch (error e)
|
||||
{
|
||||
// Ignore any error
|
||||
}
|
||||
}
|
||||
105
resources/examples/map.c3
Normal file
105
resources/examples/map.c3
Normal file
@@ -0,0 +1,105 @@
|
||||
module map(Key, Type);
|
||||
|
||||
public struct Entry
|
||||
{
|
||||
Key key;
|
||||
Type *value;
|
||||
usize hash;
|
||||
Entry *next;
|
||||
}
|
||||
|
||||
public struct Map
|
||||
{
|
||||
usize size;
|
||||
void* map;
|
||||
uint mod;
|
||||
}
|
||||
|
||||
public func Map@ Map.new()
|
||||
{
|
||||
return @calloc(Map);
|
||||
}
|
||||
|
||||
public func Type *Map.valueForKey(Map *map, Key key)
|
||||
{
|
||||
if (!map.map) return nil;
|
||||
usize hash = key.hash();
|
||||
usize pos = hash & map.mod;
|
||||
Entry *entry = &map.map[pop];
|
||||
if () return nil;
|
||||
while (entry)
|
||||
{
|
||||
if (entry.hash == hash && entry.key == key) return entry.value;
|
||||
entry = entry.next;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
public func Type *Map.setValueForKey(Map *map, Key key, Type *value)
|
||||
{
|
||||
if (!map.map)
|
||||
{
|
||||
map.map = @calloc(Entry, 16);
|
||||
map.mod = 0x0F;
|
||||
}
|
||||
|
||||
usize hash = key.hash();
|
||||
usize pos = hash & map.mod;
|
||||
Entry *entry = &map.map[pop];
|
||||
while (1)
|
||||
{
|
||||
if (!entry.value)
|
||||
{
|
||||
entry.value = value;
|
||||
entry.hash = hash;
|
||||
entry.key = key;
|
||||
return nil;
|
||||
}
|
||||
if (entry.hash == hash && entry.key == key)
|
||||
{
|
||||
Type *old = entry.value;
|
||||
entry.value = value;
|
||||
return old;
|
||||
}
|
||||
if (entry.next)
|
||||
{
|
||||
entry = entry.next;
|
||||
}
|
||||
entry.next = @malloc(Entry);
|
||||
entry = entry.next;
|
||||
}
|
||||
}
|
||||
|
||||
public func usize Map.size(Vector *vector)
|
||||
{
|
||||
return vector.array.size;
|
||||
}
|
||||
|
||||
public func void Map.removeLast(Vector *vector)
|
||||
{
|
||||
vector.array.pop();
|
||||
}
|
||||
|
||||
public macro Vector.@foreach(Vector *vector : @body(Type value))
|
||||
{
|
||||
for (usize i = 0, i < vector.array.size; i++)
|
||||
{
|
||||
@body(vector.array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
test
|
||||
{
|
||||
define IntVector = Vector(int);
|
||||
IntVector *vector = @calloc(IntVector);
|
||||
vector.add(1);
|
||||
vector.add(2);
|
||||
foreach (int i : vector)
|
||||
{
|
||||
printDigit(i);
|
||||
}
|
||||
vector.@foreach(int i)
|
||||
{
|
||||
printDigit(i);
|
||||
}
|
||||
}
|
||||
762
resources/examples/toml_parser_c2.c3
Normal file
762
resources/examples/toml_parser_c2.c3
Normal file
@@ -0,0 +1,762 @@
|
||||
// This is the toml_parser.c2 changed to c3 to compare
|
||||
|
||||
module toml;
|
||||
|
||||
import stdio;
|
||||
import stdlib;
|
||||
import string;
|
||||
import file_utils;
|
||||
import csetjmp;
|
||||
|
||||
const uint NamesCacheSize = 8;
|
||||
const uint MaxNodes = 1024;
|
||||
const uint MaxNames = 4096;
|
||||
const uint MaxValues = 4096 * 128;
|
||||
const uint MaxDepth = 8;
|
||||
|
||||
//#define DEBUG_NODES
|
||||
|
||||
$if (DEBUG_NODES)
|
||||
|
||||
func void Blocks.dump(const Blocks* b)
|
||||
{
|
||||
printf("Nodes (%u/%u) (%u bytes)\n", b.nodeCount, b.maxNodes, b.nodeCount * sizeof(Node));
|
||||
for (uint i = 0; i < b.nodeCount; i++)
|
||||
{
|
||||
// @ensure const(n)
|
||||
Node* n = &b.nodes[i];
|
||||
uint nameOffset = getValue(n.nameOffset);
|
||||
NodeKind kind = getKind(n.nameOffset);
|
||||
switch (kind)
|
||||
{
|
||||
case NodeKind.TABLE:
|
||||
case NodeKind.TABLE_ARRAY:
|
||||
printf(" [%3u] %s name %3u next %3u child %3u (%s)\n",
|
||||
i, kind.name, nameOffset, n.nextNode, n.child, &b.names[nameOffset]);
|
||||
case NodeKind.VALUE_ARRAY:
|
||||
case NodeKind.VALUE:
|
||||
ValueType t = getRawType(n.rawValue);
|
||||
uint offset = getRawValue(n.rawValue);
|
||||
printf(" [%3u] %s name %3u next %3u value %5u(%s) (%s)\n",
|
||||
i, kind.name, nameOffset, n.nextNode, offset, type2str(t), &b.names[nameOffset]);
|
||||
case NodeKind.ARRAY_CHILD:
|
||||
printf(" [%3u] %s name --- next %3u child %3u\n",
|
||||
i, kind.name, n.nextNode, n.child);
|
||||
}
|
||||
}
|
||||
printf("Names (%u/%u)\n", b.namesOffset, b.namesSize);
|
||||
uint i = 1;
|
||||
uint start = i;
|
||||
while (i < b.namesOffset)
|
||||
{
|
||||
if (b.names[i] == 0) {
|
||||
printf(" [%3u] %s\n", start, &b.names[start]);
|
||||
i++;
|
||||
start = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
printf("Values (%u/%u)\n", b.valuesOffset, b.valuesSize);
|
||||
i = 1;
|
||||
start = i;
|
||||
while (i < b.valuesOffset)
|
||||
{
|
||||
if (b.values[i] == 0)
|
||||
{
|
||||
printf(" [%3u] %s\n", start, &b.values[start]);
|
||||
i++;
|
||||
start = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$endif
|
||||
|
||||
/**
|
||||
* @ensure const(a), const(b)
|
||||
*/
|
||||
func bool same(char* a, char* b)
|
||||
{
|
||||
uint i = 0;
|
||||
while (a[i] == b[i])
|
||||
{
|
||||
if (a[i] == 0) return true;
|
||||
++i;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct Parser
|
||||
{
|
||||
Tokenizer tokenizer;
|
||||
Token tok;
|
||||
JmpBuf jump_err;
|
||||
char* errorMsg;
|
||||
|
||||
Blocks* blocks;
|
||||
Node*[MaxDepth] parents;
|
||||
Node*[MaxDepth] lastChild;
|
||||
uint numParents;
|
||||
Node* topParent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ensure const(input)
|
||||
*/
|
||||
func Parser.parse(Parser* p, char* input, char* diagMsg, Blocks* blocks) throws
|
||||
{
|
||||
p.tokenizer.init(input);
|
||||
p.tok.init();
|
||||
p.errorMsg = diagMsg;
|
||||
p.errorMsg[0] = 0;
|
||||
|
||||
p.blocks = blocks;
|
||||
memset(p.parents, 0, sizeof(Node*)*MaxDepth);
|
||||
memset(p.lastChild, 0, sizeof(Node*)*MaxDepth);
|
||||
p.numParents = 0;
|
||||
p.topParent = nil;
|
||||
|
||||
try p.consumeToken();
|
||||
try p.parseTopLevel();
|
||||
return true;
|
||||
|
||||
catch (error e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
func void Parser.parseTopLevel(Parser* p) throws ParseError
|
||||
{
|
||||
// key = value
|
||||
// | [[array]]
|
||||
// | [table]
|
||||
while (p.tok.isNot(TokenKind.EOF))
|
||||
{
|
||||
switch (p.tok.kind)
|
||||
{
|
||||
case TokenKind.WORD:
|
||||
p.parseKeyValue();
|
||||
case TokenKind.LBRACE:
|
||||
p.parseTable();
|
||||
case TokenKind.Lbrace2:
|
||||
p.parseTableArray();
|
||||
default:
|
||||
sprintf(p.errorMsg, "syntax error %s", p.tok.loc.str());
|
||||
throw ParseError.SYNTAX_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func uint getRawValue(uint raw) @(inline)
|
||||
{
|
||||
return raw & ~RawValueMask;
|
||||
}
|
||||
|
||||
func ValueType getRawType(uint raw) @(inline)
|
||||
{
|
||||
return cast(ValueType, (raw >> ValueTypeOffset) & 0x3);
|
||||
}
|
||||
|
||||
func uint addType(uint raw, ValueType t) @(inline)
|
||||
{
|
||||
return raw | (t << ValueTypeOffset);
|
||||
}
|
||||
|
||||
func void Parser.parseKeyValue(Parser* p) throws ParseError
|
||||
{
|
||||
//printf("parseKeyValue()\n");
|
||||
char[MaxText] key;
|
||||
strcpy(key, p.tok.text);
|
||||
try p.consumeToken();
|
||||
try p.expectAndConsume(TokenKind.Equals);
|
||||
u32 value = try p.parseValue();
|
||||
bool isArray = value & ValueIsArray != 0;
|
||||
u32 off = p.blocks.addNode(key, isArray ? NodeKind.ValueArray : NodeKind.Value);
|
||||
Node* node = &p.blocks.nodes[off];
|
||||
node.rawValue = value;
|
||||
if (p.lastChild[p.numParents])
|
||||
{
|
||||
p.lastChild[p.numParents].nextNode = off;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p.topParent) p.topParent.child = off;
|
||||
}
|
||||
p.lastChild[p.numParents] = node;
|
||||
}
|
||||
|
||||
func void Parser.parseTable(Parser* p) throws ParseError
|
||||
{
|
||||
//printf("parseTable()\n");
|
||||
try p.consumeToken();
|
||||
try p.expect(TokenKind.Word);
|
||||
char* name = p.tok.text;
|
||||
uint depth = 0;
|
||||
bool isTop = p.nextToken().isNot(TokenKind.DOT);
|
||||
depth += p.addTable(name, depth, isTop, NodeKind.Table);
|
||||
p.consumeToken();
|
||||
|
||||
while (p.tok.is(TokenKind.DOT))
|
||||
{
|
||||
depth++;
|
||||
p.consumeToken();
|
||||
p.expect(TokenKind.WORD);
|
||||
name = p.tok.text;
|
||||
isTop = p.nextToken().isNot(TokenKind.DOT);
|
||||
depth += p.addTable(name, depth, isTop, NodeKind.TABLE);
|
||||
p.consumeToken();
|
||||
}
|
||||
p.expectAndConsume(TokenKind.Rbrace);
|
||||
}
|
||||
|
||||
func void Parser.parseTableArray(Parser* p)
|
||||
{
|
||||
//printf("parseTableArray()\n");
|
||||
p.consumeToken();
|
||||
p.expect(TokenKind.Word);
|
||||
const char* name = p.tok.text;
|
||||
u32 depth = 0;
|
||||
bool isTop = p.nextToken().isNot(TokenKind.Dot);
|
||||
depth += p.addTable(name, depth, isTop, NodeKind.TableArray);
|
||||
p.consumeToken();
|
||||
|
||||
while (p.tok.is(TokenKind.Dot)) {
|
||||
depth++;
|
||||
p.consumeToken();
|
||||
p.expect(TokenKind.Word);
|
||||
name = p.tok.text;
|
||||
isTop = p.nextToken().isNot(TokenKind.Dot);
|
||||
depth += p.addTable(name, depth, isTop, NodeKind.TableArray);
|
||||
p.consumeToken();
|
||||
}
|
||||
p.expectAndConsume(TokenKind.Rbrace2);
|
||||
}
|
||||
|
||||
func u32 Parser.parseValue(Parser* p) {
|
||||
//printf("parseValue()\n");
|
||||
u32 value = 0;
|
||||
switch (p.tok.kind) {
|
||||
case TokenKind.Word:
|
||||
sprintf(p.errorMsg, "unexpected word at %s", p.tok.loc.str());
|
||||
longjmp(p.jump_err, 1);
|
||||
break;
|
||||
case TokenKind.Text:
|
||||
value = p.blocks.addValue(p.tok.text);
|
||||
value = addType(value, ValueType.Text);
|
||||
p.consumeToken();
|
||||
break;
|
||||
case TokenKind.Number:
|
||||
// TODO negative numbers
|
||||
value = addType(p.tok.number, ValueType.Number);
|
||||
p.consumeToken();
|
||||
break;
|
||||
case TokenKind.Kw_true: fallthrough;
|
||||
case TokenKind.Kw_false:
|
||||
value = addType(p.tok.number, ValueType.Boolean);
|
||||
p.consumeToken();
|
||||
break;
|
||||
case TokenKind.Lbrace:
|
||||
value = p.parseArrayValues();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
func u32 Parser.parseArrayValues(Parser* p) {
|
||||
//printf("parseArrayValues()\n");
|
||||
p.consumeToken();
|
||||
u32 value = p.parseValue() | ValueIsArray;
|
||||
while (p.tok.is(TokenKind.Comma)) {
|
||||
p.consumeToken();
|
||||
if (p.tok.is(TokenKind.Rbrace)) break; // trailing comma is allowed
|
||||
p.parseValue();
|
||||
}
|
||||
p.expectAndConsume(TokenKind.Rbrace);
|
||||
p.blocks.addNull();
|
||||
return value;
|
||||
}
|
||||
|
||||
func u32 Parser.addTable(Parser* p, const char* name, u32 depth, bool isTop, NodeKind kind) {
|
||||
//printf("addTable %s\n", name);
|
||||
Blocks* blocks = p.blocks;
|
||||
if (!isTop && p.numParents > depth && same(blocks.getName(p.parents[depth]), name)) {
|
||||
if (getKind(p.parents[depth].nameOffset) == NodeKind.TableArray) return 1;
|
||||
// Do nothing
|
||||
} else {
|
||||
if (kind == NodeKind.TableArray) {
|
||||
// TODO also check if previous is also TableArray
|
||||
if (p.numParents > depth && same(blocks.getName(p.parents[depth]), name)) {
|
||||
p.numParents = depth + 1;
|
||||
} else {
|
||||
u32 off = blocks.addNode(name, kind);
|
||||
if (p.numParents > depth) p.parents[depth].nextNode = off;
|
||||
Node* node = &blocks.nodes[off];
|
||||
p.parents[depth] = node;
|
||||
|
||||
if (p.lastChild[depth]) {
|
||||
p.lastChild[depth].nextNode = off;
|
||||
} else {
|
||||
if (depth > 0) p.parents[depth - 1].child = off;
|
||||
}
|
||||
p.numParents = depth + 1;
|
||||
p.topParent = node;
|
||||
p.lastChild[depth] = node;
|
||||
p.lastChild[depth + 1] = nil;
|
||||
}
|
||||
if (isTop) {
|
||||
// add iterator node as child or next
|
||||
u32 off = blocks.addNode("", NodeKind.ArrayChild);
|
||||
Node* iter = &blocks.nodes[off];
|
||||
if (p.lastChild[depth].child) { // already has children
|
||||
p.lastChild[depth + 1].nextNode = off;
|
||||
} else {
|
||||
p.lastChild[depth].child = off;
|
||||
}
|
||||
p.lastChild[depth + 1] = iter;
|
||||
p.parents[depth + 1] = iter;
|
||||
p.lastChild[depth + 2] = nil;
|
||||
p.topParent = iter;
|
||||
p.numParents++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
u32 off = blocks.addNode(name, kind);
|
||||
if (p.numParents > depth) p.parents[depth].nextNode = off;
|
||||
Node* node = &blocks.nodes[off];
|
||||
p.parents[depth] = node;
|
||||
|
||||
if (p.lastChild[depth]) {
|
||||
p.lastChild[depth].nextNode = off;
|
||||
} else {
|
||||
if (depth > 0) p.parents[depth-1].child = off;
|
||||
}
|
||||
p.numParents = depth + 1;
|
||||
p.topParent = node;
|
||||
p.lastChild[depth] = node;
|
||||
p.lastChild[depth + 1] = nil;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
func Location Parser.consumeToken(Parser* p) {
|
||||
Location prev = p.tok.loc;
|
||||
p.tokenizer.lex(&p.tok);
|
||||
if (p.tok.is(TokenKind.Error)) {
|
||||
strcpy(p.errorMsg, p.tok.text);
|
||||
longjmp(p.jump_err, 1);
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
func Token* Parser.nextToken(Parser* p) {
|
||||
return p.tokenizer.lookahead();
|
||||
}
|
||||
|
||||
func void Parser.expectAndConsume(Parser* p, TokenKind k) {
|
||||
if (p.tok.isNot(k)) {
|
||||
sprintf(p.errorMsg, "expected '%s' at %s", token2str(k), p.tok.loc.str());
|
||||
longjmp(p.jump_err, 1);
|
||||
}
|
||||
p.consumeToken();
|
||||
}
|
||||
|
||||
func void Parser.expect(Parser* p, TokenKind k) {
|
||||
if (p.tok.isNot(k)) {
|
||||
sprintf(p.errorMsg, "expected '%s' at %s", token2str(k), p.tok.loc.str());
|
||||
longjmp(p.jump_err, 1);
|
||||
}
|
||||
}
|
||||
|
||||
const u32 MaxDiag = 128;
|
||||
|
||||
public struct TomlReader @opaque
|
||||
{
|
||||
char[MaxDiag] message;
|
||||
Blocks* blocks;
|
||||
}
|
||||
|
||||
public func TomlReader* TomlReader.create()
|
||||
{
|
||||
TomlReader* r = @malloc(TomlReader);
|
||||
r.blocks = @malloc(Blocks);
|
||||
r.blocks.init();
|
||||
return r;
|
||||
}
|
||||
|
||||
public func void TomlReader.destroy(TomlReader* r)
|
||||
{
|
||||
r.blocks.destroy();
|
||||
free(r.blocks);
|
||||
free(r);
|
||||
}
|
||||
|
||||
public func const char* TomlReader.getMsg(const TomlReader* r)
|
||||
{
|
||||
return r.message;
|
||||
}
|
||||
|
||||
public func void TomlReader.parse(TomlReader* r, string filename) throws ParseError, FileError
|
||||
{
|
||||
Reader file;
|
||||
|
||||
try file.open(filename);
|
||||
|
||||
defer file.close();
|
||||
|
||||
if (file.isEmpty())
|
||||
{
|
||||
printf("file %s is empty\n", filename);
|
||||
throw ParseError.EMPTY_FILE;
|
||||
}
|
||||
|
||||
Parser parser;
|
||||
parser.parse(file.data(), r.message, r.blocks);
|
||||
|
||||
$if (DEBUG_NODES)
|
||||
r.blocks.dump();
|
||||
$endif
|
||||
return status;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------
|
||||
// Getters+iters
|
||||
|
||||
func const Node* Reader.findNode(const Reader* r, const char* key) {
|
||||
char[MaxText] name;
|
||||
const char* cp = key;
|
||||
const char* start = cp;
|
||||
u32 len = 0;
|
||||
Node* node = nil;
|
||||
while (1) {
|
||||
switch (*cp) {
|
||||
case 0:
|
||||
len = cast<u32>(cp - start);
|
||||
memcpy(name, start, len);
|
||||
name[len] = 0;
|
||||
node = r.blocks.findNode(name, node);
|
||||
return node;
|
||||
case '.':
|
||||
len = cast<u32>(cp - start);
|
||||
memcpy(name, start, len);
|
||||
name[len] = 0;
|
||||
start = cp + 1;
|
||||
node = r.blocks.findNode(name, node);
|
||||
if (!node) return nil;
|
||||
if (getKind(node.nameOffset) == NodeKind.Value) return nil;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
public func const char* Reader.getValue(const Reader* r, const char* key) {
|
||||
const Node* node = r.findNode(key);
|
||||
if (!node) return nil;
|
||||
if (getKind(node.nameOffset) != NodeKind.Value) return nil;
|
||||
ValueType t = getRawType(node.rawValue);
|
||||
if (t != ValueType.Text) return nil;
|
||||
return &r.blocks.values[getRawValue(node.rawValue)];
|
||||
}
|
||||
|
||||
public func bool Reader.getNumber(const Reader* r, const char* key, u32* result) {
|
||||
const Node* node = r.findNode(key);
|
||||
if (!node) return false;
|
||||
if (getKind(node.nameOffset) != NodeKind.Value) return false;
|
||||
ValueType t = getRawType(node.rawValue);
|
||||
if (t != ValueType.Number) return false;
|
||||
*result = getRawValue(node.rawValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
public func bool Reader.getBool(const Reader* r, const char* key, bool* result) {
|
||||
const Node* node = r.findNode(key);
|
||||
if (!node) return false;
|
||||
if (getKind(node.nameOffset) != NodeKind.Value) return false;
|
||||
ValueType t = getRawType(node.rawValue);
|
||||
if (t != ValueType.Boolean) return false;
|
||||
*result = getRawValue(node.rawValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
public type NodeIter struct {
|
||||
const Blocks* blocks;
|
||||
const Node* node;
|
||||
}
|
||||
|
||||
public func bool NodeIter.done(const NodeIter* i) {
|
||||
return i.node == nil;
|
||||
}
|
||||
|
||||
public func void NodeIter.next(NodeIter* i) {
|
||||
if (i.node == nil) return;
|
||||
u32 next = i.node.nextNode;
|
||||
if (next == 0) i.node = nil;
|
||||
else i.node = &i.blocks.nodes[next];
|
||||
}
|
||||
|
||||
public func const char* NodeIter.getValue(const NodeIter* i, const char* key) {
|
||||
const Node* child = i.blocks.findNode(key, i.node);
|
||||
if (!child) return nil;
|
||||
if (getKind(child.nameOffset) != NodeKind.Value) return nil;
|
||||
ValueType t = getRawType(child.rawValue);
|
||||
if (t != ValueType.Text) return nil;
|
||||
return &i.blocks.values[getRawValue(child.rawValue)];
|
||||
}
|
||||
|
||||
public func bool NodeIter.getNumber(const NodeIter* i, const char* key, u32* result) {
|
||||
const Node* child = i.blocks.findNode(key, i.node);
|
||||
if (!child) return false;
|
||||
if (getKind(child.nameOffset) != NodeKind.Value) return false;
|
||||
ValueType t = getRawType(child.rawValue);
|
||||
if (t != ValueType.Number) return false;
|
||||
*result = getRawValue(child.rawValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
public func bool NodeIter.getBool(const NodeIter* i, const char* key, bool* result) {
|
||||
const Node* child = i.blocks.findNode(key, i.node);
|
||||
if (!child) return false;
|
||||
if (getKind(child.nameOffset) != NodeKind.Value) return false;
|
||||
ValueType t = getRawType(child.rawValue);
|
||||
if (t != ValueType.Boolean) return false;
|
||||
*result = getRawValue(child.rawValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
public func NodeIter Reader.getNodeIter(const Reader* r, const char* key) {
|
||||
const Node* node = r.findNode(key);
|
||||
if (node && getKind(node.nameOffset) == NodeKind.TableArray) {
|
||||
node = &r.blocks.nodes[node.child];
|
||||
}
|
||||
NodeIter iter = { r.blocks, node}
|
||||
return iter;
|
||||
}
|
||||
|
||||
|
||||
public type ValueIter struct {
|
||||
const char* values;
|
||||
bool isArray;
|
||||
}
|
||||
|
||||
func ValueIter ValueIter.create(const char* values, bool isArray) {
|
||||
ValueIter iter = { values, isArray }
|
||||
return iter;
|
||||
}
|
||||
|
||||
public func bool ValueIter.done(const ValueIter* i) {
|
||||
return i.values[0] == 0;
|
||||
}
|
||||
|
||||
public func void ValueIter.next(ValueIter* i) {
|
||||
if (i.values[0] == 0) return;
|
||||
while (i.values[0] != 0) i.values++;
|
||||
if (i.isArray) i.values++; // skip 0-terminator
|
||||
}
|
||||
|
||||
public func const char* ValueIter.getValue(const ValueIter* i) {
|
||||
return i.values;
|
||||
}
|
||||
|
||||
public func ValueIter Reader.getValueIter(const Reader* r, const char* key) {
|
||||
const Node* node = r.findNode(key);
|
||||
if (node) {
|
||||
switch (getKind(node.nameOffset)) {
|
||||
case NodeKind.Table: fallthrough;
|
||||
case NodeKind.TableArray:
|
||||
break;
|
||||
case NodeKind.ValueArray:
|
||||
// TODO support arrays of Numbers/Booleans as well
|
||||
return ValueIter.create(&r.blocks.values[getRawValue(node.rawValue)], true);
|
||||
case NodeKind.Value:
|
||||
return ValueIter.create(&r.blocks.values[getRawValue(node.rawValue)], false);
|
||||
case NodeKind.ArrayChild:
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ValueIter.create(&r.blocks.values[0], false);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------
|
||||
// Blocks
|
||||
|
||||
type NodeKind enum u8 {
|
||||
Table = 0,
|
||||
TableArray,
|
||||
ValueArray,
|
||||
Value,
|
||||
ArrayChild,
|
||||
}
|
||||
|
||||
type ValueType enum u8 {
|
||||
Text = 0,
|
||||
Number,
|
||||
Boolean,
|
||||
}
|
||||
const u32 ValueIsArray = (1 << 31);
|
||||
const u32 ValueTypeOffset = 29;
|
||||
const u32 RawValueMask = (0x7 << 29);
|
||||
|
||||
func const char* type2str(ValueType t) {
|
||||
switch (t) {
|
||||
case ValueType.Text: return "T";
|
||||
case ValueType.Number: return "N";
|
||||
case ValueType.Boolean: return "B";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
public type Node struct {
|
||||
u32 nameOffset;
|
||||
u32 nextNode;
|
||||
union {
|
||||
u32 child;
|
||||
u32 rawValue; // bit 31 isArray, bit 29-30 ValueType
|
||||
}
|
||||
} @(opaque, packed)
|
||||
|
||||
public type Blocks struct {
|
||||
Node* nodes;
|
||||
u32 nodeCount;
|
||||
|
||||
char* names;
|
||||
u32 namesOffset;
|
||||
u32 namesSize;
|
||||
|
||||
u32[NamesCacheSize] namesCache;
|
||||
u32 lastCache;
|
||||
|
||||
char* values;
|
||||
u32 valuesOffset;
|
||||
u32 valuesSize;
|
||||
} @(opaque)
|
||||
|
||||
func void Blocks.init(Blocks* b) {
|
||||
memset(b, 0, sizeof(Blocks));
|
||||
b.nodes = calloc(MaxNodes, sizeof(Node));
|
||||
|
||||
b.namesSize = MaxNames;
|
||||
b.names = calloc(1, b.namesSize);
|
||||
b.names[0] = 0;
|
||||
b.namesOffset = 1; // 0 indicates no name
|
||||
|
||||
b.valuesSize = MaxValues;
|
||||
b.values = calloc(1, b.valuesSize);
|
||||
b.values[0] = 0;
|
||||
b.valuesOffset = 1; // 0 indicates no value
|
||||
|
||||
b.lastCache = 0;
|
||||
//memset(b.namesCache, 0, sizeof(b.namesCache)); // sizeof(struct member) not supported yet
|
||||
memset(b.namesCache, 0, sizeof(u32)*NamesCacheSize);
|
||||
}
|
||||
|
||||
func void Blocks.destroy(Blocks* b) {
|
||||
free(b.values);
|
||||
free(b.names);
|
||||
free(b.nodes);
|
||||
}
|
||||
|
||||
func u32 Blocks.searchNameCache(Blocks* b, const char* name) {
|
||||
for (u32 i=0; i<NamesCacheSize; ++i) {
|
||||
u32 off = b.namesCache[i];
|
||||
if (off && same(&b.names[off], name)) return off;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
func const char* Blocks.getName(const Blocks* b, const Node* node) {
|
||||
return &b.names[getValue(node.nameOffset)];
|
||||
}
|
||||
|
||||
|
||||
func u32 Blocks.addNode(Blocks* b, const char* name, NodeKind k) {
|
||||
if (b.nodeCount == MaxNodes) {
|
||||
// TODO jmp?
|
||||
printf("node limit reached\n");
|
||||
exit(-1);
|
||||
}
|
||||
u32 off = b.nodeCount;
|
||||
Node* node = &b.nodes[off];
|
||||
b.nodeCount++;
|
||||
|
||||
if (name[0] == 0) {
|
||||
node.nameOffset = 0;
|
||||
} else {
|
||||
u32 nameOffset = b.searchNameCache(name);
|
||||
if (nameOffset != 0) {
|
||||
node.nameOffset = nameOffset;
|
||||
} else {
|
||||
u32 len = cast<u32>(strlen(name)) + 1;
|
||||
nameOffset = b.namesOffset;
|
||||
node.nameOffset = nameOffset;
|
||||
char* newname = &b.names[nameOffset];
|
||||
memcpy(newname, name, len);
|
||||
b.namesCache[b.lastCache] = nameOffset;
|
||||
b.lastCache = (b.lastCache + 1) % NamesCacheSize;
|
||||
b.namesOffset += len;
|
||||
}
|
||||
}
|
||||
node.nameOffset = addKind(node.nameOffset, k);
|
||||
return off;
|
||||
}
|
||||
|
||||
func u32 Blocks.addValue(Blocks* b, const char* value) {
|
||||
if (value[0] == 0) return 0;
|
||||
u32 off = b.valuesOffset;
|
||||
u32 len = cast<u32>(strlen(value)) + 1;
|
||||
memcpy(&b.values[off], value, len);
|
||||
b.valuesOffset += len;
|
||||
return off;
|
||||
}
|
||||
|
||||
func void Blocks.addNull(Blocks* b) {
|
||||
b.values[b.valuesOffset] = 0;
|
||||
b.valuesOffset++;
|
||||
}
|
||||
|
||||
func Node* Blocks.findNode(const Blocks* b, const char* name, const Node* parent) {
|
||||
if (b.nodeCount == 0) return nil;
|
||||
Node* node = &b.nodes[0];
|
||||
if (parent) {
|
||||
if (!parent.child) return nil;
|
||||
node = &b.nodes[parent.child];
|
||||
}
|
||||
while (1) {
|
||||
const char* nodeName = &b.names[getValue(node.nameOffset)];
|
||||
if (same(name, nodeName)) return node;
|
||||
if (!node.nextNode) return nil;
|
||||
node = &b.nodes[node.nextNode];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const u32 NodeKindOffset = 29;
|
||||
|
||||
func u32 addKind(u32 value, NodeKind k) @(inline) {
|
||||
return value | (k << NodeKindOffset);
|
||||
}
|
||||
|
||||
func NodeKind getKind(u32 value) @(inline) {
|
||||
return cast<NodeKind>(value >> NodeKindOffset);
|
||||
}
|
||||
|
||||
func u32 getValue(u32 value) @(inline) {
|
||||
return value & ~(0x7 << NodeKindOffset);
|
||||
}
|
||||
359
resources/examples/toml_tokenizer_c2.c3
Normal file
359
resources/examples/toml_tokenizer_c2.c3
Normal file
@@ -0,0 +1,359 @@
|
||||
// This is the toml_tokenizer.c2 changed to c3 to compare
|
||||
module toml;
|
||||
import stdio;
|
||||
import string;
|
||||
import ctype;
|
||||
import stdlib;
|
||||
|
||||
const uint MaxText = 1024;
|
||||
|
||||
enum TokenKind : byte (string name)
|
||||
{
|
||||
WORD("word"),
|
||||
TEXT("text"),
|
||||
NUMBER("number"),
|
||||
KW_TRUE("true"),
|
||||
KW_FALSE("false"),
|
||||
LBRACE("["),
|
||||
LBRACE2("[[")
|
||||
RBRACE("]"),
|
||||
RBRACE2("]]"),
|
||||
EQUALS("="),
|
||||
DOT("."),
|
||||
COMMA(","),
|
||||
EOF("eof"),
|
||||
ERROR("error"),
|
||||
}
|
||||
|
||||
func void Location.init(Location* l, uint line = 0, uint col = 0)
|
||||
{
|
||||
l.line = line;
|
||||
l.column = col;
|
||||
}
|
||||
|
||||
func string Location.str(Location* l)
|
||||
{
|
||||
static char[32] msg;
|
||||
sprintf(msg, "line %u:%u", l.line, l.column);
|
||||
return msg;
|
||||
}
|
||||
|
||||
struct Token
|
||||
{
|
||||
Location loc;
|
||||
TokenKind kind;
|
||||
// TODO union?
|
||||
union
|
||||
{
|
||||
string text;
|
||||
uint number;
|
||||
}
|
||||
}
|
||||
|
||||
func void Token.init(Token* t)
|
||||
{
|
||||
t.loc.init(0, 0);
|
||||
t.kind = TokenKind.EOF;
|
||||
t.text = nil;
|
||||
t.number = 0;
|
||||
}
|
||||
|
||||
func void Token.clear(Token* t)
|
||||
{
|
||||
t.text = nil;
|
||||
t.number = 0;
|
||||
}
|
||||
|
||||
func void Token.setLocation(Token* t, Location l)
|
||||
{
|
||||
t.loc = l;
|
||||
}
|
||||
|
||||
func bool Token.is(Token* t, TokenKind k)
|
||||
{
|
||||
return t.kind == k;
|
||||
}
|
||||
|
||||
func bool Token.isNot(Token* t, TokenKind k)
|
||||
{
|
||||
return t.kind != k;
|
||||
}
|
||||
|
||||
func string Token.getName(Token* t)
|
||||
{
|
||||
return t.kind.name;
|
||||
}
|
||||
|
||||
struct Tokenizer
|
||||
{
|
||||
char* dataStart;
|
||||
char* current;
|
||||
Location loc;
|
||||
char[MaxText] text;
|
||||
Token nextToken;
|
||||
bool haveNext;
|
||||
}
|
||||
|
||||
func void Tokenizer.init(Tokenizer* t, char* input)
|
||||
{
|
||||
t.dataStart = input;
|
||||
t.current = input;
|
||||
t.loc.init(1, 1);
|
||||
t.haveNext = false;
|
||||
t.text[0] = 0;
|
||||
}
|
||||
|
||||
func void Tokenizer.lex(Tokenizer* t, Token* result)
|
||||
{
|
||||
if (t.haveNext)
|
||||
{
|
||||
// Q: ptr assign or copy?
|
||||
*result = t.nextToken;
|
||||
t.haveNext = false;
|
||||
return;
|
||||
}
|
||||
result.clear();
|
||||
while (1)
|
||||
{
|
||||
switch (t.current[0])
|
||||
{
|
||||
case 0:
|
||||
result.loc = t.loc;
|
||||
result.kind = TokenKind.EOF;
|
||||
return;
|
||||
case '#':
|
||||
if (t.loc.column != 1)
|
||||
{
|
||||
sprintf(t.text, "unexpected '#' after line start at %s", t.loc.str());
|
||||
result.kind = TokenKind.ERROR;
|
||||
result.text = t.text;
|
||||
return;
|
||||
}
|
||||
t.parseComment();
|
||||
case ' ':
|
||||
case '\t':
|
||||
t.advance(1);
|
||||
case '\n':
|
||||
t.current++;
|
||||
t.loc.line++;
|
||||
t.loc.column = 1;
|
||||
case '=':
|
||||
result.loc = t.loc;
|
||||
result.kind = TokenKind.EQUALS;
|
||||
t.advance(1);
|
||||
return;
|
||||
case '.':
|
||||
result.loc = t.loc;
|
||||
result.kind = TokenKind.DOT;
|
||||
t.advance(1);
|
||||
return;
|
||||
case ',':
|
||||
result.loc = t.loc;
|
||||
result.kind = TokenKind.COMMA;
|
||||
t.advance(1);
|
||||
return;
|
||||
case '[':
|
||||
result.loc = t.loc;
|
||||
if (t.current[1] == '[')
|
||||
{
|
||||
t.advance(2);
|
||||
result.kind = TokenKind.LBRACE2;
|
||||
}
|
||||
else
|
||||
{
|
||||
t.advance(1);
|
||||
result.kind = TokenKind.LBRACE;
|
||||
}
|
||||
return;
|
||||
case ']':
|
||||
result.loc = t.loc;
|
||||
if (t.current[1] == ']')
|
||||
{
|
||||
t.advance(2);
|
||||
result.kind = TokenKind.RBRACE2;
|
||||
}
|
||||
else
|
||||
{
|
||||
t.advance(1);
|
||||
result.kind = TokenKind.RBRACE;
|
||||
}
|
||||
return;
|
||||
case '"':
|
||||
if (t.current[1] == '"' && t.current[2] == '"')
|
||||
{
|
||||
t.parseMultiText(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
t.parseText(result);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
// key or number
|
||||
result.loc = t.loc;
|
||||
if (isdigit(t.current[0]))
|
||||
{
|
||||
t.parseNumber(result);
|
||||
return;
|
||||
}
|
||||
if (t.current[0] == 'f' && strncmp("false", t.current, 5) == 0) {
|
||||
t.advance(5);
|
||||
result.number = 0;
|
||||
result.kind = TokenKind.Kw_false;
|
||||
return;
|
||||
}
|
||||
if (t.current[0] == 't' && strncmp("true", t.current, 4) == 0) {
|
||||
t.advance(4);
|
||||
result.number = 1;
|
||||
result.kind = TokenKind.Kw_true;
|
||||
return;
|
||||
}
|
||||
if (isalpha(t.current[0]))
|
||||
{
|
||||
t.parseKey(result);
|
||||
return;
|
||||
}
|
||||
sprintf(t.text, "unexpected char '%c' at %s", t.current[0], t.loc.str());
|
||||
result.kind = TokenKind.Error;
|
||||
result.text = t.text;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Token* Tokenizer.lookahead(Tokenizer* t)
|
||||
{
|
||||
if (!t.haveNext)
|
||||
{
|
||||
t.lex(&t.nextToken);
|
||||
t.haveNext = true;
|
||||
}
|
||||
return &t.nextToken;
|
||||
}
|
||||
|
||||
func void Tokenizer.advance(Tokenizer* t, uint amount)
|
||||
{
|
||||
t.loc.column += amount;
|
||||
t.current += amount;
|
||||
}
|
||||
|
||||
func void Tokenizer.parseComment(Tokenizer* t)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
switch (t.current[0])
|
||||
{
|
||||
case 0:
|
||||
return;
|
||||
case '\n':
|
||||
t.current++;
|
||||
t.loc.line++;
|
||||
t.loc.column = 1;
|
||||
return;
|
||||
default:
|
||||
t.current++;
|
||||
t.loc.column++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func void Tokenizer.parseText(Tokenizer* t, Token* result)
|
||||
{
|
||||
// TODO handle literal strings ' .. ' -> no escaping
|
||||
// TODO handle escape chars for normal strings " .. \" \r \n "
|
||||
t.advance(1);
|
||||
result.loc = t.loc;
|
||||
const char* start = t.current;
|
||||
while (t.current[0] && t.current[0] != '"') t.current++;
|
||||
|
||||
uint len = cast(uint, t.current - start);
|
||||
// assert(len < MaxText);
|
||||
memcpy(t.text, start, len);
|
||||
t.text[len] = 0;
|
||||
result.kind = TokenKind.Text;
|
||||
result.text = t.text;
|
||||
t.loc.column += len;
|
||||
t.advance(1);
|
||||
}
|
||||
|
||||
func void Tokenizer.parseMultiText(Tokenizer* t, Token* result)
|
||||
{
|
||||
t.advance(3);
|
||||
if (t.current[0] == '\n')
|
||||
{
|
||||
t.current++;
|
||||
t.loc.line++;
|
||||
t.loc.column = 1;
|
||||
}
|
||||
result.loc = t.loc;
|
||||
char* start = t.current;
|
||||
while (1)
|
||||
{
|
||||
if (t.current[0] == 0)
|
||||
{
|
||||
sprintf(t.text, "missing end \"\"\" %s", t.loc.str());
|
||||
result.kind = TokenKind.Error;
|
||||
result.text = t.text;
|
||||
return;
|
||||
}
|
||||
if (t.current[0] == '\n')
|
||||
{
|
||||
t.loc.line++;
|
||||
t.loc.column = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
t.loc.column++;
|
||||
}
|
||||
if (t.current[0] == '"' && t.current[1] == '"' && t.current[2] == '"') break;
|
||||
t.current++;
|
||||
}
|
||||
|
||||
uint len = cast(uint, t.current - start);
|
||||
// assert(len < MaxText);
|
||||
memcpy(t.text, start, len);
|
||||
t.text[len] = 0;
|
||||
result.kind = TokenKind.Text;
|
||||
result.text = t.text;
|
||||
t.advance(3);
|
||||
}
|
||||
|
||||
func void Tokenizer.parseNumber(Tokenizer* t, Token* result)
|
||||
{
|
||||
// TODO handle prefix +/-
|
||||
// handle hexadecimal/ocal/binary number
|
||||
// handle '_', like 1_000_000
|
||||
|
||||
u32 number = cast<u32>(atoi(t.current));
|
||||
result.kind = TokenKind.Number;
|
||||
result.number = number;
|
||||
while (t.current[0] && isdigit(t.current[0]))
|
||||
{
|
||||
t.current++;
|
||||
t.loc.column++;
|
||||
}
|
||||
}
|
||||
|
||||
func bool isKeyChar(u8 c)
|
||||
{
|
||||
if (c >= 128) return true;
|
||||
if (isalpha(c)) return true;
|
||||
if (isdigit(c)) return true;
|
||||
if (c == '_' || c == '-') return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
func void Tokenizer.parseKey(Tokenizer* t, Token* result)
|
||||
{
|
||||
char* start = t.current;
|
||||
while (t.current[0] && isKeyChar(cast<u8>(t.current[0]))) t.current++;
|
||||
|
||||
uint len = cast(uint, t.current - start);
|
||||
// assert(len < MaxText);
|
||||
memcpy(t.text, start, len);
|
||||
t.text[len] = 0;
|
||||
result.kind = TokenKind.Word;
|
||||
result.text = t.text;
|
||||
t.loc.column += len;
|
||||
}
|
||||
70
resources/examples/vector.c3
Normal file
70
resources/examples/vector.c3
Normal file
@@ -0,0 +1,70 @@
|
||||
module vector(Type);
|
||||
|
||||
public struct Vector
|
||||
{
|
||||
Type[*] array;
|
||||
}
|
||||
|
||||
public func Vector@ newVector()
|
||||
{
|
||||
return @calloc(Vector);
|
||||
}
|
||||
|
||||
public func void Vector.add(Vector *vector, Type type)
|
||||
{
|
||||
vector.array += type;
|
||||
}
|
||||
|
||||
public func usize Vector.size(Vector *vector)
|
||||
{
|
||||
return vector.array.size;
|
||||
}
|
||||
|
||||
public func void Vector.removeLast(Vector *vector)
|
||||
{
|
||||
vector.array.pop();
|
||||
}
|
||||
|
||||
public func void Vector.removefirst(Vector *vector)
|
||||
{
|
||||
vector.array.removeAt(0);
|
||||
}
|
||||
|
||||
public func void Type *Vector.first(Vector *vector)
|
||||
{
|
||||
return &vector.array.first;
|
||||
}
|
||||
|
||||
public func void Type *Vector.last(Vector *vector)
|
||||
{
|
||||
return &vector.array.last();
|
||||
}
|
||||
|
||||
public func bool Vector.empty(Vector *vector)
|
||||
{
|
||||
return !vector.array.size;
|
||||
}
|
||||
|
||||
public macro Vector.@foreach(Vector *vector : @body(Type value))
|
||||
{
|
||||
for (usize i = 0, i < vector.array.size; i++)
|
||||
{
|
||||
@body(vector.array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
test
|
||||
{
|
||||
define IntVector = Vector(int);
|
||||
IntVector *vector = @calloc(IntVector);
|
||||
vector.add(1);
|
||||
vector.add(2);
|
||||
foreach (int i : vector)
|
||||
{
|
||||
printDigit(i);
|
||||
}
|
||||
vector.@foreach(int i)
|
||||
{
|
||||
printDigit(i);
|
||||
}
|
||||
}
|
||||
35
resources/examples/window.c3
Normal file
35
resources/examples/window.c3
Normal file
@@ -0,0 +1,35 @@
|
||||
import gtk;
|
||||
|
||||
const string CLICK_ME = "Click Me";
|
||||
uint counter = 0;
|
||||
|
||||
func void clickedme(GtkButton *o, void *d)
|
||||
{
|
||||
cast(GtkLabel*, d).set_text(string.format("You clicked me %d times", ++counter));
|
||||
}
|
||||
|
||||
int main(int argc, string[] argv)
|
||||
{
|
||||
gtk::init(&argc, &argv);
|
||||
|
||||
GtkWindow *win = gtk::windowCreate(GtkWindow::TOPLEVEL);
|
||||
win.set_title(CLICK_ME);
|
||||
|
||||
GtkButton *button = gtk::buttonCreateWithLabel(CLICK_ME);
|
||||
|
||||
GtkLabel *label = GtkLabel.new("There have been no clicks yet");
|
||||
label.setSingleLineMode(true);
|
||||
|
||||
GtkVBox vbox = gtk::vBoxCreate(true, 1);
|
||||
vbox.add(label);
|
||||
vbox.add(button);
|
||||
|
||||
win.add(vbox);
|
||||
|
||||
win.connectSignal("delete-event", gtk::mainQuit, NULL);
|
||||
button.connectSignal("clicked", &clickedme, label);
|
||||
|
||||
win.showAll();
|
||||
gtk::main();
|
||||
return 0;
|
||||
}
|
||||
@@ -25,6 +25,7 @@ void yyerror(char *s);
|
||||
%token THROWS THROW TRY CATCH SCOPE PUBLIC DEFER ATTRIBUTE IN
|
||||
|
||||
%token FN_BLOCK_START FN_BLOCK_END
|
||||
%token MULTW ADDW SUBW
|
||||
|
||||
%start translation_unit
|
||||
%%
|
||||
@@ -34,6 +35,10 @@ path
|
||||
| path IDENT SCOPE
|
||||
;
|
||||
|
||||
import_path
|
||||
: IDENT
|
||||
| import_path SCOPE IDENT
|
||||
;
|
||||
|
||||
ident_expression
|
||||
: CONST_IDENT
|
||||
@@ -83,6 +88,7 @@ unary_operator
|
||||
| '*'
|
||||
| '+'
|
||||
| '-'
|
||||
| SUBW
|
||||
| '~'
|
||||
| '!'
|
||||
;
|
||||
@@ -91,6 +97,7 @@ unary_operator
|
||||
multiplicative_expression
|
||||
: unary_expression
|
||||
| multiplicative_expression '*' unary_expression
|
||||
| multiplicative_expression MULTW unary_expression
|
||||
| multiplicative_expression '/' unary_expression
|
||||
| multiplicative_expression '%' unary_expression
|
||||
;
|
||||
@@ -111,7 +118,9 @@ bit_expression
|
||||
additive_expression
|
||||
: bit_expression
|
||||
| additive_expression '+' bit_expression
|
||||
| additive_expression ADDW bit_expression
|
||||
| additive_expression '-' bit_expression
|
||||
| additive_expression SUBW bit_expression
|
||||
;
|
||||
|
||||
relational_expression
|
||||
@@ -631,15 +640,29 @@ module_params
|
||||
;
|
||||
|
||||
module
|
||||
: MODULE IDENT ';'
|
||||
| MODULE IDENT '(' module_params ')' ';'
|
||||
: MODULE import_path ';'
|
||||
| MODULE import_path '(' module_params ')' ';'
|
||||
;
|
||||
|
||||
specified_import
|
||||
: IDENT AS IDENT
|
||||
| IDENT
|
||||
| TYPE
|
||||
| CONST
|
||||
| MACRO
|
||||
| TYPE AS TYPE
|
||||
| CONST AS CONST
|
||||
| MACRO AS MACRO
|
||||
;
|
||||
|
||||
specified_import_list
|
||||
: specified_import
|
||||
| specified_import_list ',' specified_import
|
||||
;
|
||||
|
||||
import_decl
|
||||
: IMPORT IDENT ';'
|
||||
| IMPORT IDENT AS IDENT ';'
|
||||
| IMPORT IDENT AS IDENT LOCAL ';'
|
||||
| IMPORT IDENT LOCAL ';'
|
||||
: IMPORT import_path ';'
|
||||
| IMPORT import_path ':' specified_import_list ';'
|
||||
;
|
||||
|
||||
imports
|
||||
|
||||
@@ -94,7 +94,7 @@ func int test3()
|
||||
|
||||
typedef func void(int) as Foo;
|
||||
//typedef int as Foo;
|
||||
func void printf(char *hello);
|
||||
extern func void printf(char *hello);
|
||||
|
||||
macro @hello()
|
||||
{
|
||||
@@ -110,8 +110,13 @@ func void bob()
|
||||
long deee = (eok ? a : b) + c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
func int main(int x)
|
||||
{
|
||||
int aa = x++;
|
||||
int bb = x--;
|
||||
int cc = ++x;
|
||||
for (int ok = 0; ok < 10; ok++)
|
||||
{
|
||||
printf("ok");
|
||||
@@ -132,6 +137,7 @@ func int main(int x)
|
||||
{
|
||||
printf("helo\n");
|
||||
}
|
||||
Test baok = { 1 };
|
||||
Test2 efe;
|
||||
efe.t.a = 3;
|
||||
if (efe.t.a > 2) printf("Works!\n");
|
||||
@@ -183,6 +189,7 @@ JUMP:
|
||||
|
||||
func void test2(int* x, int y, int z)
|
||||
{
|
||||
x++;
|
||||
z = 0;
|
||||
z ? y : z;
|
||||
x += 1;
|
||||
|
||||
11
resources/testproject/bar.c3
Normal file
11
resources/testproject/bar.c3
Normal file
@@ -0,0 +1,11 @@
|
||||
module bar;
|
||||
|
||||
import baz::foo;
|
||||
import testbaz;
|
||||
|
||||
public func void test()
|
||||
{
|
||||
Foo x;
|
||||
foo::test();
|
||||
Zab z;
|
||||
}
|
||||
20
resources/testproject/foo.c3
Normal file
20
resources/testproject/foo.c3
Normal file
@@ -0,0 +1,20 @@
|
||||
module baz::foo;
|
||||
|
||||
import bar;
|
||||
|
||||
public struct Foo
|
||||
{
|
||||
int a;
|
||||
}
|
||||
|
||||
extern func void printf(char *hello);
|
||||
|
||||
local func void ofke()
|
||||
{}
|
||||
|
||||
func void exple() {}
|
||||
|
||||
public func void test()
|
||||
{
|
||||
printf("Hello from baz::foo::test()!\n");
|
||||
}
|
||||
11
resources/testproject/hello_world.c3
Normal file
11
resources/testproject/hello_world.c3
Normal file
@@ -0,0 +1,11 @@
|
||||
module hello_world;
|
||||
import bar;
|
||||
|
||||
extern func void printf(char *hello);
|
||||
|
||||
func int main(int x)
|
||||
{
|
||||
printf("Hello World!\n");
|
||||
bar::test();
|
||||
return 1;
|
||||
}
|
||||
10
resources/testproject/project.toml
Normal file
10
resources/testproject/project.toml
Normal file
@@ -0,0 +1,10 @@
|
||||
[[executable]]
|
||||
name = "hello_world"
|
||||
version = "0.1.0"
|
||||
authors = ["John Doe <john.doe@example.com>"]
|
||||
langrev = "1"
|
||||
warnings = ["no-unused"]
|
||||
# sources compiled
|
||||
sources = ["./**"]
|
||||
# libraries to use
|
||||
libs = []
|
||||
6
resources/testproject/zab.c3
Normal file
6
resources/testproject/zab.c3
Normal file
@@ -0,0 +1,6 @@
|
||||
module testbaz::zab;
|
||||
|
||||
public struct Zab
|
||||
{
|
||||
double a;
|
||||
}
|
||||
Reference in New Issue
Block a user