Aria

A low-level systems programming language
git clone git://git.m21c.me/Aria.git
Log | Files | Refs | README | LICENSE

compiler.c (183584B)


      1 #include <assert.h>
      2 #include <ctype.h>
      3 #include <stdarg.h>
      4 #include <stdio.h>
      5 #include <stdint.h>
      6 #include <stdlib.h>
      7 #include <stdbool.h>
      8 #include <string.h>
      9 
     10 /* @note redeinition of assert() for ease of debugging. */
     11 
     12 #if 0
     13 #ifdef assert
     14 #undef assert
     15 #endif
     16 static void
     17 myassert(const char *expr, const char *file, int line)
     18 {
     19 	_assert(expr, file, line);
     20 }
     21 
     22 #define assert(_Expression) (void) ( \
     23 	(!!(_Expression)) || (myassert(#_Expression,__FILE__,__LINE__),0) \
     24 )
     25 #endif
     26 
     27 // @section forward declarations {{{
     28 
     29 typedef unsigned char uchar;
     30 typedef unsigned int uint;
     31 
     32 typedef
     33 struct Source Source;
     34 
     35 typedef
     36 struct Compiler Compiler;
     37 
     38 typedef
     39 struct Node Node;
     40 
     41 typedef
     42 struct Type Type;
     43 
     44 typedef
     45 struct Decl Decl;
     46 
     47 typedef
     48 struct Env Env;
     49 
     50 typedef
     51 struct AnnotParam AnnotParam;
     52 
     53 typedef
     54 struct Annot Annot;
     55 
     56 typedef
     57 struct Docket Docket;
     58 
     59 typedef
     60 struct Gist Gist;
     61 
     62 typedef
     63 struct Conduct Conduct;
     64 
     65 typedef
     66 struct Block Block;
     67 
     68 
     69 
     70 // }}}
     71 
     72 // @section node kind table {{{
     73 
     74 #define SENDOFFILE "end-of-file"
     75 #define SINVALID   "invalide token"
     76 #define SLINEDELIM "line-delimiter"
     77 
     78 #define SCHAR   "character-literal"
     79 #define SIDENT  "identifier"
     80 #define SNUMBER "number-literal"
     81 #define SSTRING "string-literal"
     82 
     83 #define SASTMT      "statement"
     84 #define SALOOPUNTIL "loop-until-clause"
     85 #define SADECL      "declaration"
     86 #define SADECLREF   "symbol-reference"
     87 #define SASWITCH    "case-clause"
     88 #define SACASE      "of-clause"
     89 #define SACONV      "conversion"
     90 
     91 #define NODETAB \
     92 	/*    tag        , string      , childs , flags   , prec */ \
     93 	/* Basic */ \
     94 	entry(ENDOFFILE  , SENDOFFILE  ,      0 ,       0 ,         0) \
     95 	entry(INVALID    , SINVALID    ,      0 ,       0 ,         0) \
     96 	entry(LINEDELIM  , SLINEDELIM  ,      0 ,       0 ,         0) \
     97 	entry(SEMIDELIM  , ";"         ,      0 ,       0 ,         0) \
     98 	entry(COMMADELIM , ","         ,      0 ,       0 ,         0) \
     99 	entry(COLONDELIM , ":"         ,      0 ,       0 ,         0) \
    100 	entry(LCURLDELIM , "{"         ,      0 ,       0 ,         0) \
    101 	entry(LSQRDELIM  , "["         ,      0 ,       0 ,         0) \
    102 	entry(LPARDELIM  , "("         ,      0 ,       0 ,         0) \
    103 	entry(RCURLDELIM , "}"         ,      0 ,       0 ,         0) \
    104 	entry(RSQRDELIM  , "]"         ,      0 ,       0 ,         0) \
    105 	entry(RPARDELIM  , ")"         ,      0 ,       0 ,         0) \
    106 	entry(ANNOT      , "@"         ,      0 ,       0 ,         0) \
    107 	entry(CHAR       , SCHAR       ,      0 ,       0 ,         0) \
    108 	entry(IDENT      , SIDENT      ,      0 ,       0 ,         0) \
    109 	entry(NUMBER     , SNUMBER     ,      0 ,       0 ,         0) \
    110 	entry(STRING     , SSTRING     ,      0 ,       0 ,         0) \
    111 	entry(TYPE       , "type"      ,      0 ,       0 ,         0) \
    112 	/* Keywords */ \
    113 	entry(KVOID      , "void"      ,      0 ,       0 ,         0) \
    114 	entry(KBOOL      , "bool"      ,      0 ,       0 ,         0) \
    115 	entry(KU8        , "u8"        ,      0 ,       0 ,         0) \
    116 	entry(KS8        , "s8"        ,      0 ,       0 ,         0) \
    117 	entry(KU16       , "u16"       ,      0 ,       0 ,         0) \
    118 	entry(KS16       , "s16"       ,      0 ,       0 ,         0) \
    119 	entry(KU32       , "u32"       ,      0 ,       0 ,         0) \
    120 	entry(KS32       , "s32"       ,      0 ,       0 ,         0) \
    121 	entry(KU64       , "u64"       ,      0 ,       0 ,         0) \
    122 	entry(KS64       , "s64"       ,      0 ,       0 ,         0) \
    123 	entry(KF32       , "f32"       ,      0 ,       0 ,         0) \
    124 	entry(KF64       , "f64"       ,      0 ,       0 ,         0) \
    125 	entry(KUCHAR     , "uchar"     ,      0 ,       0 ,         0) \
    126 	entry(KCHAR      , "char"      ,      0 ,       0 ,         0) \
    127 	entry(KUSHORT    , "ushort"    ,      0 ,       0 ,         0) \
    128 	entry(KSHORT     , "short"     ,      0 ,       0 ,         0) \
    129 	entry(KUINT      , "uint"      ,      0 ,       0 ,         0) \
    130 	entry(KINT       , "int"       ,      0 ,       0 ,         0) \
    131 	entry(KULONG     , "ulong"     ,      0 ,       0 ,         0) \
    132 	entry(KLONG      , "long"      ,      0 ,       0 ,         0) \
    133 	entry(KULLONG    , "ullong"    ,      0 ,       0 ,         0) \
    134 	entry(KLLONG     , "llong"     ,      0 ,       0 ,         0) \
    135 	entry(KFLOAT     , "float"     ,      0 ,       0 ,         0) \
    136 	entry(KDOUBLE    , "double"    ,      0 ,       0 ,         0) \
    137 	entry(KLDOUBLE   , "ldouble"   ,      0 ,       0 ,         0) \
    138 	entry(KUSIZE     , "usize"     ,      0 ,       0 ,         0) \
    139 	entry(KSSIZE     , "ssize"     ,      0 ,       0 ,         0) \
    140 	entry(KFALSE     , "false"     ,      0 ,       0 ,         0) \
    141 	entry(KTRUE      , "true"      ,      0 ,       0 ,         0) \
    142 	entry(KNULL      , "null"      ,      0 ,       0 ,         0) \
    143 	entry(KUSE       , "use"       ,      0 ,       0 ,         0) \
    144 	entry(KBUNDLE    , "bundle"    ,      0 ,       0 ,         0) \
    145 	entry(KNOT       , "not"       ,      0 ,       0 ,         0) \
    146 	entry(KAND       , "and"       ,      0 ,       0 ,         0) \
    147 	entry(KOR        , "or"        ,      0 ,       0 ,         0) \
    148 	entry(KIS        , "is"        ,      0 ,       0 ,         0) \
    149 	entry(KSIZEOF    , "sizeof"    ,      0 ,       0 ,         0) \
    150 	entry(KALIGNOF   , "alignof"   ,      0 ,       0 ,         0) \
    151 	entry(KLENGTHOF  , "lengthof"  ,      0 ,       0 ,         0) \
    152 	entry(KBITCAST   , "bitcast"   ,      0 ,       0 ,         0) \
    153 	entry(KEXTERN    , "extern"    ,      0 ,       0 ,         0) \
    154 	entry(KINTERN    , "intern"    ,      0 ,       0 ,         0) \
    155 	entry(KSTATIC    , "static"    ,      0 ,       0 ,         0) \
    156 	entry(KCONST     , "const"     ,      0 ,       0 ,         0) \
    157 	entry(KVAR       , "var"       ,      0 ,       0 ,         0) \
    158 	entry(KBREAK     , "break"     ,      0 ,       0 ,         0) \
    159 	entry(KCONTINUE  , "continue"  ,      0 ,       0 ,         0) \
    160 	entry(KGOTO      , "goto"      ,      0 ,       0 ,         0) \
    161 	entry(KRETURN    , "return"    ,      0 ,       0 ,         0) \
    162 	entry(KIF        , "if"        ,      0 ,       0 ,         0) \
    163 	entry(KELSE      , "else"      ,      0 ,       0 ,         0) \
    164 	entry(KCASE      , "case"      ,      0 ,       0 ,         0) \
    165 	entry(KOF        , "of"        ,      0 ,       0 ,         0) \
    166 	entry(KDO        , "do"        ,      0 ,       0 ,         0) \
    167 	entry(KFOR       , "for"       ,      0 ,       0 ,         0) \
    168 	entry(KLOOP      , "loop"      ,      0 ,       0 ,         0) \
    169 	entry(KWHILE     , "while"     ,      0 ,       0 ,         0) \
    170 	entry(KUNTIL     , "until"     ,      0 ,       0 ,         0) \
    171 	entry(KSTRUCT    , "struct"    ,      0 ,       0 ,         0) \
    172 	entry(KUNION     , "union"     ,      0 ,       0 ,         0) \
    173 	/* Operators */ \
    174 	entry(OSUFINC    , "++"        ,      1 , FRASSOC , PUNSUF   ) \
    175 	entry(OSUFDEC    , "--"        ,      1 , FRASSOC , PUNSUF   ) \
    176 	entry(OARRAY     , "[]"        ,      1 , FRASSOC , PUNSUF   ) \
    177 	entry(OCALL      , "()"        ,      1 , FRASSOC , PUNSUF   ) \
    178 	entry(ODISP      , "."         ,      1 , FRASSOC , PUNSUF   ) \
    179 	entry(ODEREF     , "*"         ,      1 ,       0 , PUNARY   ) \
    180 	entry(OINC       , "++"        ,      1 ,       0 , PUNARY   ) \
    181 	entry(ODEC       , "--"        ,      1 ,       0 , PUNARY   ) \
    182 	entry(OBNOT      , "~"         ,      1 ,       0 , PUNARY   ) \
    183 	entry(OLNOT      , "!"         ,      1 ,       0 , PUNARY   ) \
    184 	entry(OFLIP      , "!>"        ,      1 ,       0 , PUNARY   ) \
    185 	entry(OADDR      , "&"         ,      1 ,       0 , PUNARY   ) \
    186 	entry(OPLUS      , "+"         ,      1 ,       0 , PUNARY   ) \
    187 	entry(OMINUS     , "-"         ,      1 ,       0 , PUNARY   ) \
    188 	entry(OCAST      , "(type)"    ,      1 ,       0 , PUNARY   ) \
    189 	entry(OMUL       , "*"         ,      2 ,       0 , PMUL     ) \
    190 	entry(ODIV       , "/"         ,      2 ,       0 , PMUL     ) \
    191 	entry(OMOD       , "%"         ,      2 ,       0 , PMUL     ) \
    192 	entry(OLSH       , "<<"        ,      2 ,       0 , PMUL     ) \
    193 	entry(OARSH      , ">>>"       ,      2 ,       0 , PMUL     ) \
    194 	entry(ORSH       , ">>"        ,      2 ,       0 , PMUL     ) \
    195 	entry(OBAND      , "&"         ,      2 ,       0 , PMUL     ) \
    196 	entry(OADD       , "+"         ,      2 ,       0 , PADD     ) \
    197 	entry(OSUB       , "-"         ,      2 ,       0 , PADD     ) \
    198 	entry(OBOR       , "|"         ,      2 ,       0 , PADD     ) \
    199 	entry(OXOR       , "^"         ,      2 ,       0 , PADD     ) \
    200 	entry(ORANGE     , ".."        ,      2 ,       0 , PRANGE   ) \
    201 	entry(OLEQ       , "<="        ,      2 ,       0 , PRELAT   ) \
    202 	entry(OLET       , "<"         ,      2 ,       0 , PRELAT   ) \
    203 	entry(OGEQ       , ">="        ,      2 ,       0 , PRELAT   ) \
    204 	entry(OGRT       , ">"         ,      2 ,       0 , PRELAT   ) \
    205 	entry(ONEQ       , "!="        ,      2 ,       0 , PRELAT   ) \
    206 	entry(OEQU       , "=="        ,      2 ,       0 , PRELAT   ) \
    207 	entry(OIDENT     , "==="       ,      2 ,       0 , PRELAT   ) \
    208 	entry(OLAND      , "&&"        ,      2 ,       0 , PAND     ) \
    209 	entry(OLOR       , "||"        ,      2 ,       0 , POR      ) \
    210 	entry(OASS       , "="         ,      2 , FRASSOC , PASSIGN  ) \
    211 	entry(OMULA      , "*="        ,      2 , FRASSOC , PASSIGN  ) \
    212 	entry(ODIVA      , "/="        ,      2 , FRASSOC , PASSIGN  ) \
    213 	entry(OMODA      , "%="        ,      2 , FRASSOC , PASSIGN  ) \
    214 	entry(OLSHA      , "<<="       ,      2 , FRASSOC , PASSIGN  ) \
    215 	entry(OARSHA     , ">>>="      ,      2 , FRASSOC , PASSIGN  ) \
    216 	entry(ORSHA      , ">>="       ,      2 , FRASSOC , PASSIGN  ) \
    217 	entry(OANDA      , "&="        ,      2 , FRASSOC , PASSIGN  ) \
    218 	entry(OADDA      , "+="        ,      2 , FRASSOC , PASSIGN  ) \
    219 	entry(OSUBA      , "-="        ,      2 , FRASSOC , PASSIGN  ) \
    220 	entry(OORA       , "|="        ,      2 , FRASSOC , PASSIGN  ) \
    221 	entry(OXORA      , "^="        ,      2 , FRASSOC , PASSIGN  ) \
    222 	/* Ast */ \
    223 	entry(ACOMMA     , ","         ,      0 ,       0 ,         0) \
    224 	entry(ASTMT      , SASTMT      ,      0 ,       0 ,         0) \
    225 	entry(ADECL      , SADECL      ,      0 ,       0 ,         0) \
    226 	entry(ADECLREF   , SADECLREF   ,      0 ,       0 ,         0) \
    227 	entry(AENV       , "env"       ,      0 ,       0 ,         0) \
    228 	entry(ALOOPUNTIL , SALOOPUNTIL ,      0 ,       0 ,         0) \
    229 	entry(AFOREACH   , "for-each"  ,      0 ,       0 ,         0) \
    230 	entry(AFORSTEP   , "for-step"  ,      0 ,       0 ,         0) \
    231 	entry(ASCOPE     , "scope"     ,      0 ,       0 ,         0) \
    232 	entry(ALABEL     , "label"     ,      0 ,       0 ,         0) \
    233 	entry(ASWITCH    , SASWITCH    ,      0 ,       0 ,         0) \
    234 	entry(ACASE      , SACASE      ,      0 ,       0 ,         0) \
    235 	entry(ACONV      , SACONV      ,      0 ,       0 ,         0) \
    236 	entry(ADEREF     , "*"         ,      0 ,       0 ,         0) \
    237 	entry(AADDR      , "&"         ,      0 ,       0 ,         0) \
    238 	entry(ACOMPOUND  , "{...}"     ,      0 ,       0 ,         0) \
    239 	entry(AFIELDINIT , ":"         ,      0 ,       0 ,         0) \
    240 	entry(ASELFDISP  , ":"         ,      0 ,       0 ,         0) \
    241 	/* endof NODETAB */
    242 
    243 #define isbinaryop(kind) ((kind) >= OMUL && (kind) < ACOMMA)
    244 
    245 
    246 
    247 // }}}
    248 
    249 // @section type kind table {{{
    250 
    251 #define TYPETAB \
    252 	/*    tag        , size , align*/ \
    253 	entry(TNONE      ,    0 ,         0) \
    254 	entry(TERRTYPE   ,    0 ,         0) \
    255 	entry(TUNDEFINED ,    0 ,         0) \
    256 	entry(TVOID      ,    0 ,         0) \
    257 	entry(TBOOL      ,    1 ,         1) \
    258 	entry(TINFER     ,    4 ,         4) \
    259 	entry(TUINFER    ,    4 ,         4) \
    260 	entry(TS8        ,    1 ,         1) \
    261 	entry(TU8        ,    1 ,         1) \
    262 	entry(TS16       ,    2 ,         2) \
    263 	entry(TU16       ,    2 ,         2) \
    264 	entry(TS32       ,    4 ,         4) \
    265 	entry(TU32       ,    4 ,         4) \
    266 	entry(TS64       ,    8 ,         8) \
    267 	entry(TU64       ,    8 ,         8) \
    268 	entry(TF32       ,    4 ,         4) \
    269 	entry(TF64       ,    8 ,         8) \
    270 	entry(TPTR       ,    8 ,         8) \
    271 	entry(TARRAY     ,    0 ,         0) \
    272 	entry(TTUPLE     ,    0 ,         0) \
    273 	entry(TFUNCTION  ,    0 ,         0) \
    274 	entry(TSTRUCT    ,    0 ,         0) \
    275 	entry(TUNION     ,    0 ,         0) \
    276 	/* endof TYPETAB */
    277 
    278 #define TCHAR    TS8
    279 #define TUCHAR   TU8
    280 #define TSHORT   TS16
    281 #define TUSHORT  TU16
    282 #define TINT     TS32
    283 #define TUINT    TU32
    284 #define TLONG    TS64
    285 #define TULONG   TU64
    286 #define TLLONG   TS64
    287 #define TULLONG  TU64
    288 
    289 #define TFLOAT   TF32
    290 #define TDOUBLE  TF64
    291 #define TLDOUBLE TF64
    292 
    293 #define TSSIZE   TS64
    294 #define TUSIZE   TU64
    295 /* @todo maybe add long double type ? */
    296 
    297 #define TYPEKEWORDYTAB \
    298 	entry(VOID)  entry(BOOL)   \
    299 	entry(S8)    entry(U8)     \
    300 	entry(S16)   entry(U16)    \
    301 	entry(S32)   entry(U32)    \
    302 	entry(S64)   entry(U64)    \
    303 	entry(F32)   entry(F64)    \
    304 	entry(CHAR)  entry(UCHAR)  \
    305 	entry(SHORT) entry(USHORT) \
    306 	entry(INT)   entry(UINT)   \
    307 	entry(LONG)  entry(ULONG)  \
    308 	entry(LLONG) entry(ULLONG) \
    309 	entry(FLOAT) entry(DOUBLE) entry(LDOUBLE) \
    310 	entry(SSIZE) entry(USIZE)  \
    311 	/* endof TYPEKEYWORDTAB */
    312 
    313 
    314 
    315 // }}}
    316 
    317 // @section enumerations & constants {{{
    318 
    319 typedef
    320 enum Flags {
    321 	FRASSOC = 1
    322 } Flads;
    323 
    324 typedef
    325 enum Precedence {
    326 	PUNSUF  = 10,
    327 	PUNARY  =  9,
    328 	PMUL    =  8,
    329 	PADD    =  7,
    330 	PRANGE  =  6,
    331 	PRELAT  =  5,
    332 	PAND    =  4,
    333 	POR     =  3,
    334 	PASSIGN =  2,
    335 
    336 	PSTART  =  1
    337 } Precedence;
    338 
    339 typedef
    340 enum Kind {
    341 	#define entry(tag, string, childs, flags, prec) \
    342 		tag,
    343 	NODETAB
    344 	#undef entry
    345 
    346 	MAXKINDS
    347 } Kind;
    348 
    349 #define KSTART KVOID
    350 #define OSTART OSUFINC
    351 #define ASTART ASTMT
    352 
    353 #define iskeyword(kind) ((kind) >= KSTART && (kind) < OSTART)
    354 #define isoperator(kind) ((kind) >= OSTART && (kind) < ASTART)
    355 #define isastnode(kind) ((kind) >= ASTART && (kind) < MAXKINDS)
    356 
    357 static bool
    358 isatomnode(Kind kind)
    359 {
    360 	return kind == IDENT  || kind == ADECLREF || kind == NUMBER ||
    361 	       kind == STRING || kind == CHAR;
    362 }
    363 
    364 
    365 typedef
    366 enum TypeKind {
    367 	#define entry(tag, size, align) \
    368 		tag,
    369 	TYPETAB
    370 	#undef entry
    371 
    372 	TMAX
    373 } TypeKind;
    374 
    375 
    376 typedef
    377 enum DeclKind {
    378 	DMODULE = 0,
    379 	DTYPE, /* @note maybe be the same as void-module ? */
    380 	DVAR,
    381 	DPARAM,
    382 	DFUNCTION,
    383 	DFIELDALIAS,
    384 	DBUNDLE,
    385 	/*
    386 	DMACRO,
    387 	DENFOLD
    388 	*/
    389 } DeclKind;
    390 
    391 typedef
    392 enum DeclFlags {
    393 	MSPECIAL = 0x0001,
    394 	MRECORDMEMBER = 0x0002,
    395 	/* MINPORT  = 0x0004, ... */
    396 } DeclFlags;
    397 
    398 typedef
    399 enum EnvKind {
    400 	STOPLEVEL = 0,
    401 	SPARAMLIST,
    402 	SFUNCTION,
    403 	SSCOPE,
    404 	SIFHEADER,
    405 	SLOOPHEADER,
    406 	SDO,
    407 	SLOOP,
    408 	SWHILE,
    409 	SIF,
    410 	SELSE,
    411 	SSTRUCT,
    412 	SUNION
    413 	/*
    414 	SUNION,
    415 	SSTRUCT,
    416 	SENUM,
    417 	*/
    418 } EnvKind;
    419 
    420 typedef
    421 enum Qualifier {
    422 	QINTERN = 0x0001,
    423 	QEXTERN = 0x0002,
    424 
    425 	QSTATIC = 0x0010,
    426 
    427 	QCONST  = 0x0200,
    428 
    429 	QVAR    = 0x1000,
    430 
    431 	/* masks */
    432 	QALL     = QINTERN | QEXTERN | QSTATIC | QCONST | QVAR,
    433 	QVISIB   = QEXTERN | QINTERN,
    434 	QSTORAGE = QSTATIC,
    435 	QTYPE    = QCONST,
    436 	QINFER   = QVAR
    437 } Qualifier;
    438 
    439 typedef
    440 enum AnnotParamKind {
    441 	NSTATEEXPR,
    442 	NPARAM,
    443 	NEXPR
    444 } AnnotParamKind;
    445 
    446 typedef
    447 enum BlockKind {
    448 	BTOPLEVEL  = 0,
    449 	BFUNCTION  = 1,
    450 	BSCOPE     = 2,
    451 	BIF        = 3,
    452 	BLOOP      = 4,
    453 	BWHILELOOP = 5,
    454 	BLOOPUNTIL = 6,
    455 	BFORLOOP   = 7,
    456 	BELSE      = 8
    457 } BlockKind;
    458 
    459 typedef
    460 enum ConductKind {
    461 	CUNREACH   = 0, /* alway after a break, continue, goto or return */
    462 	CSCOPE     = 1, /* only the first conduct of a block and conducts after
    463 	                 * cunducts containing blocks are of this kind */
    464 	CBLOCK     = 2, /* always containing one or more blocks and nothing
    465 	                   else */
    466 	CLABEL     = 3  /* always after a label */
    467 } ConductKind;
    468 
    469 
    470 
    471 // }}}
    472 
    473 // @section type definitions {{{
    474 
    475 #define ARENA_PAGE_SIZE 512
    476 
    477 typedef
    478 struct MemArena {
    479 	uint8_t **pages;
    480 	size_t capacity, top;
    481 	size_t elemsize;
    482 } MemArena;
    483 
    484 typedef
    485 struct SourceArenas {
    486 	MemArena node, type, env, decl;
    487 	MemArena annot, docket;
    488 	MemArena record, field;
    489 	MemArena block, conduct, gist;
    490 } SourceArenas;
    491 
    492 typedef
    493 struct SrcLoc {
    494 	uint line, column;
    495 	const char *filename;
    496 } SrcLoc;
    497 
    498 /**
    499  * @brief A node in the abstract syntax tree.
    500  * @details The location is used to report errors. The type is used to store the
    501  *          type of the node. The union u is used to store the value of the node
    502  *          for its given kind. The lhs pointer points to the left hand side of
    503  *          its child node and the rhs pointer points to the right hand side of
    504  *          its child node (if any). Or the lhs and rhs pointer are used to
    505  *          point to the previous and next statement in a linked list (in case
    506  *          of ASTMT). Additionally, the payload pointer is used to store the
    507  *          condition of an if-statement and other statements.
    508  */
    509 struct Node {
    510 	Kind kind;
    511 	SrcLoc loc;
    512 
    513 	Type *type;
    514 
    515 	union {
    516 		int key;
    517 
    518 		double d;
    519 		uintmax_t u;
    520 		intmax_t s;
    521 
    522 		Node *payload;
    523 		Decl *declref;
    524 		Env *env;
    525 	} u;
    526 
    527 	Node *lhs, *rhs;
    528 	/* ASTMT: rhs points to next stmt (linked list) */
    529 };
    530 
    531 struct Type {
    532 	TypeKind kind;
    533 	SrcLoc loc;
    534 
    535 	Type *target; /* pointer, array, tuple-lht, function param-list, ... */
    536 
    537 	size_t size, align;
    538 
    539 	union {
    540 		struct {
    541 			int offset, size; /* in bits */
    542 		} bit;
    543 
    544 		struct {
    545 			size_t length;
    546 			size_t elemsize;
    547 		} array;
    548 
    549 		Node *val;
    550 		Type *rtarget; /* for tuples (rht) and function return-type */
    551 	} u;
    552 
    553 	Decl *module; /* module and record info */
    554 };
    555 
    556 typedef struct Field Field;
    557 
    558 typedef struct Record {
    559 	Field *head, *tail;
    560 
    561 	bool isunion;
    562 } Record;
    563 
    564 struct Field {
    565 	Decl *decl;
    566 
    567 	size_t offset, size; /* in bytes */
    568 
    569 	bool use;
    570 
    571 	Field *prev, *next;
    572 };
    573 
    574 struct Decl {
    575 	DeclKind kind;
    576 	SrcLoc loc;
    577 
    578 	Type *type;
    579 	Decl *module; /* module or bundle */
    580 	Record *record;
    581 
    582 	int key;
    583 	DeclFlags flags;
    584 
    585 	Env *parentenv, *contentenv;
    586 	union {
    587 		Node *content; /* init or function body */
    588 
    589 		bool usefield;
    590 	} u;
    591 
    592 	Decl *prev, *next;
    593 };
    594 
    595 struct Env {
    596 	EnvKind kind;
    597 	SrcLoc loc;
    598 
    599 	uint8_t keycache[64];
    600 
    601 	Decl *head, *tail;
    602 
    603 	Node *stmts;
    604 	Decl *envdecl; /* for SFUNCTION, SSTRUCT, SUNION */
    605 
    606 	/* for toplevel declarations. it will be assigned to decl->module
    607 	 * if decl->module is null (in declaration()). */
    608 	Decl *bundle;
    609 
    610 	Env *below;
    611 
    612 	bool pending;
    613 	Env *pendingnext, *pendingprev;
    614 
    615 	/* carry on source for memory management*/
    616 	SourceArenas *arenas;
    617 };
    618 
    619 struct Source {
    620 	SrcLoc currloc;
    621 
    622 	/* pre-lexer state */
    623 
    624 	char line[4096];
    625 	long linepos;
    626 
    627 	bool hasnewline;
    628 	bool handlereplprompt;
    629 
    630 	/* error-reporting and lexer state */
    631 
    632 	FILE *filein;
    633 	int tabwidth;
    634 	char stringbuf[1024];
    635 
    636 	int lastindent, lastkind;
    637 	Node tok, savedtok;
    638 
    639 	/* environment */
    640 
    641 	Env *headenv, *currenv;
    642 	Env *pendingenvhead, *pendingenvtail;
    643 
    644 	Env *implicitenv;
    645 
    646 	bool haspendingenv;
    647 
    648 	/* pending nodes */
    649 	Node *pendingnodes[512];
    650 	int pendingcount;
    651 
    652 	/* parser state */
    653 	Node *lastis;
    654 
    655 	/* import use */
    656 	Source *parent;
    657 	Source *head, *tail;
    658 	Source *prev, *next;
    659 	Compiler *compiler;
    660 
    661 	/* stack-alloc save state */
    662 	SourceArenas arenas;
    663 };
    664 
    665 struct AnnotParam {
    666 	AnnotParamKind kind;
    667 
    668 	int key;
    669 
    670 	Node *node;
    671 
    672 	AnnotParam *prev, *next;
    673 };
    674 
    675 struct Annot {
    676 	int key;
    677 	SrcLoc loc;
    678 
    679 	AnnotParam *head, *tail;
    680 
    681 	Annot *prev, *next;
    682 };
    683 
    684 struct Docket {
    685 	Node *node;
    686 	Decl *decl;
    687 
    688 	Annot *head, *tail;
    689 };
    690 
    691 struct Gist {
    692 	Decl *decl;
    693 	Conduct *parent;
    694 
    695 	bool init;
    696 	Node *where;
    697 
    698 	/* for other declarations */
    699 	Gist *prev, *next;
    700 };
    701 
    702 struct Block {
    703 	BlockKind kind;
    704 
    705 	Env *env;
    706 
    707 	/* Conduct-Sequence list*/
    708 	Conduct *head, *tail, *parent;
    709 
    710 	/* Neighbooring Blocks */
    711 	Block *prev, *next;
    712 };
    713 
    714 struct Conduct {
    715 	ConductKind kind;
    716 	uint id;
    717 
    718 	Node *label, *branch;
    719 	Node *first, *last;
    720 
    721 	bool doesbreak;
    722 	bool doescontinue;
    723 	bool doesreturn;
    724 	bool doesjump;
    725 
    726 	struct ConductGists {
    727 		Gist *head, *tail;
    728 	} gists;
    729 
    730 	struct ConductBranches {
    731 		/* Branch-relation from child to parents */
    732 		Conduct *head, *tail;
    733 
    734 		/* Branch-parent list */
    735 		Conduct *next, *prev;
    736 	} branches;
    737 
    738 	/* Block-stack */
    739 	Block *head, *tail, *parent;
    740 
    741 	/* Conduct-sequence list */
    742 	Conduct *next, *prev;
    743 };
    744 
    745 typedef struct Section   Section;
    746 typedef struct Edge      Edge;
    747 typedef struct EdgeEntry EdgeEntry;
    748 typedef struct Analysis  Analysis;
    749 
    750 typedef enum EdgeKind {
    751 	JBRANCH   = 0, /* unconditional branch */
    752 	JIFBRANCH = 1, /* conditional branch */
    753 	JNEXT     = 2, /* unconditional next section (without branch) */
    754 	JIFNEXT   = 3  /* conditional next section (without branch) */
    755 } EdgeKind;
    756 
    757 struct Edge {
    758 	EdgeKind kind;
    759 	Section *section;
    760 
    761 	Conduct *gistlist; /* @note maybe remove this, since the gistlist
    762 	                    *              is always the last of a section */
    763 
    764 	/* @todo add information about the branch/edge condition */
    765 	
    766 	/* for memory-management, since an edge is used in mult. edge-entries */
    767 	int refcount;
    768 };
    769 
    770 typedef enum EdgeEntryKind {
    771 	JINGOING  = 0, /* added as reachedfrom to section */
    772 	JOUTGOING = 1, /* added as branchto to section */
    773 	JSTART    = 2, /* added as reachedfrom edge entry to first section */
    774 	JEND      = 3  /* added as branchto edge entry to last section */
    775 } EdgeEntryKind;
    776 
    777 /* @note since an edge is used in multiple lists, edge-entry is used
    778  *              as linked-list entry */
    779 struct EdgeEntry {
    780 	EdgeEntryKind kind;
    781 	Section *belongsto;
    782 
    783 	Edge *edge; /* is NULL on JSTART or JEND */
    784 	EdgeEntry *prev, *next;
    785 };
    786 
    787 /* a section is single level. there is no hierarchy, like in the case of
    788  * scopes/environments. a function has simply a list of section from top to
    789  * bottom. */
    790 struct Section {
    791 	uint id; /* incremental number */
    792 
    793 	/* a section begins after baranch/label/start and ends
    794 	 * containing a terminating branch/label/end. this way it contains at
    795 	 * least one instructin/statement (terminating branch/label), if the 
    796 	 * (terminating branch/label/end) is not augment at the end of the
    797 	 * function-scope/clause. */
    798 	Node *first, *last;
    799 
    800 	struct {
    801 		Conduct *head, *tail;
    802 	} gistlists;
    803 
    804 	struct {
    805 		EdgeEntry *head, *tail;
    806 	} reachedfrom;
    807 
    808 	struct {
    809 		EdgeEntry *head, *tail;
    810 	} branchto;
    811 
    812 	/* prev/next section in code (no branch-info) from top to bottom
    813 	 * in function */
    814 	Section *prev, *next;
    815 };
    816 
    817 struct Analysis {
    818 	Section *head, *tail;
    819 };
    820 
    821 typedef struct CodeGen CodeGen;
    822 
    823 struct CodeGen {
    824 	FILE *out;
    825 
    826 	Env *env;
    827 	int indent, commacount;
    828 	bool needsvalue, hasclause;
    829 	const char *valuename;
    830 };
    831 
    832 struct Compiler {
    833 	Source *head, *tail;
    834 	CodeGen cg;
    835 };
    836 
    837 
    838 
    839 // }}}
    840 
    841 // @section global-vars {{{
    842 
    843 Source testsource;
    844 SourceArenas *arenas;
    845 
    846 
    847 
    848 // }}}
    849 
    850 // @section look-up tables {{{
    851 
    852 #define defaultloc {0, 1, "<builtin>"}
    853 
    854 #define entry(tag, size, align) \
    855 	{(tag), defaultloc, NULL, (size), (align), {{0}}, NULL},
    856 Type prim[] = {
    857 	TYPETAB
    858 };
    859 #undef entry
    860 
    861 #define primitive(typetag) (prim + typetag)
    862 
    863 int keywordlengths[OSTART - KSTART];
    864 
    865 const int keywordtypeids[] = {
    866 	#define entry(tag) \
    867 		[K##tag] = T##tag,
    868 	TYPEKEWORDYTAB
    869 	#undef entry
    870 
    871 	[OSTART] = 0
    872 };
    873 
    874 const char *const nodestrings[MAXKINDS] = {
    875 	#define entry(tag, string, childs, flags, prec) \
    876 		string,
    877 	NODETAB
    878 	#undef entry
    879 };
    880 
    881 /*
    882 Node kinds:
    883 	'@' - Annotation
    884 	';' ',' ':' '{' '}' ']' ')' - Delimiters
    885 	'A' - Statement
    886 	'I' - Identifier
    887 	'K' - Keyword
    888 	'N' - Number-literal
    889 	'O' - Operator
    890 	'S' - String-literal
    891 */
    892 
    893 #define opentry(numops, rassoc, prec) \
    894 	((uint8_t) ( ((numops) << 6) | ((rassoc) << 5) | (prec) ))
    895 
    896 const uint8_t opinfo[] = {
    897 	#define entry(tag, string, childs, flags, prec) ((uint8_t) ( \
    898 		((childs) << 6) | \
    899 		(!!(flags & FRASSOC) << 5) | \
    900 		(prec) \
    901 	)),
    902 	NODETAB
    903 	#undef entry
    904 };
    905 
    906 #define getnumops(kind) (opinfo[kind] >> 6)
    907 #define israssoc(kind) ((opinfo[kind] >> 5) & 0x01)
    908 #define getprec(kind) ((opinfo[kind] & 0x1f))
    909 
    910 
    911 
    912 // }}}
    913 
    914 // @section utility functions {{{
    915 
    916 #define listappendex(parent, child, head, tail, prev, next) do { \
    917 	if ((parent)->head) { \
    918 		assert((parent)->tail); \
    919 		(child)->prev = (parent)->tail; \
    920 		(child)->next = NULL; \
    921 		(parent)->tail->next = (child); \
    922 	} else { \
    923 		assert(!(parent)->tail); \
    924 		(child)->prev = NULL; \
    925 		(child)->next = NULL; \
    926 		(parent)->head = (child); \
    927 	} \
    928 	(parent)->tail = (child); \
    929 } while (0)
    930 
    931 #define listappend(parent, child) \
    932 	listappendex(parent, child, head, tail, prev, next)
    933 
    934 #ifndef lengthof
    935 #define lengthof(array) ((int) sizeof(array) / (int) sizeof(*(array)))
    936 #endif
    937 
    938 static int
    939 mystrncasecmp(const char *str1, const char *str2, size_t max_len)
    940 {
    941 	char tmp1[] = {'\0', '\0'};
    942 	char tmp2[] = {'\0', '\0'};
    943 	char c1, c2;
    944 	int result;
    945 
    946 	size_t i;
    947 
    948 	if (max_len == 0) {
    949 		size_t len1 = strlen(str1);
    950 		size_t len2 = strlen(str2);
    951 		max_len = len1 > len2 ? len1 : len2;
    952 	}
    953 
    954 	for (i = 0; i < max_len; ++i) {
    955 		c1 = tolower(str1[i]);
    956 		c2 = tolower(str2[i]);
    957 		if (c1 == '\0' && c2 == '\0') return 0;
    958 		tmp1[0] = c1;
    959 		tmp2[0] = c2;
    960 		result = strcmp(tmp1, tmp2);
    961 		if (result != 0) return result;
    962 	}
    963 
    964 	return 0;
    965 }
    966 
    967 static int
    968 mystrcasecmp(const char *str1, const char *str2)
    969 {
    970 	char tmp1[] = {'\0', '\0'};
    971 	char tmp2[] = {'\0', '\0'};
    972 	char c1, c2;
    973 	int result;
    974 
    975 	size_t i;
    976 
    977 	for (i = 0;; ++i) {
    978 		c1 = tolower(str1[i]);
    979 		c2 = tolower(str2[i]);
    980 		if (c1 == '\0' && c2 == '\0') return 0;
    981 		tmp1[0] = c1;
    982 		tmp2[0] = c2;
    983 		result = strcmp(tmp1, tmp2);
    984 		if (result != 0) return result;
    985 	}
    986 
    987 	return 0;
    988 }
    989 
    990 
    991 
    992 // }}}
    993 
    994 // @section memory arena {{{
    995 
    996 #define myalloc(arena, Type) \
    997 	((Type *) myallocimpl(arena, sizeof(Type)))
    998 
    999 static void *
   1000 myallocimpl(MemArena *arena, size_t elemsize)
   1001 {
   1002 	const size_t pageindex = arena->top / ARENA_PAGE_SIZE;
   1003 	const size_t pageoffset = arena->top % ARENA_PAGE_SIZE;
   1004 
   1005 	union {uint8_t *in; void *out;} bitcast;
   1006 
   1007 	assert(!arena->elemsize || arena->elemsize == elemsize);
   1008 	arena->elemsize = elemsize;
   1009 
   1010 	if (pageindex >= arena->capacity) {
   1011 		arena->capacity *= 2;
   1012 		if (!arena->capacity)
   1013 			arena->capacity = 1;
   1014 		arena->pages = realloc(
   1015 			arena->pages, arena->capacity * sizeof(void*));
   1016 		assert(arena->pages);
   1017 	}
   1018 
   1019 	if (!arena->pages[pageindex]) {
   1020 		arena->pages[pageindex] = calloc(
   1021 			ARENA_PAGE_SIZE, arena->elemsize);
   1022 		assert(arena->pages[pageindex]);
   1023 	}
   1024 	
   1025 	bitcast.in = arena->pages[pageindex] + pageoffset * arena->elemsize;
   1026 
   1027 	arena->top++;
   1028 
   1029 	return bitcast.out;
   1030 }
   1031 
   1032 /* @note for debugging */
   1033 static void *
   1034 getalloc(MemArena *arena, size_t index)
   1035 {
   1036 	const size_t pageindex = arena->top / ARENA_PAGE_SIZE;
   1037 	const size_t pageoffset = arena->top % ARENA_PAGE_SIZE;
   1038 
   1039 	union {uint8_t *in; void *out;} bitcast;
   1040 
   1041 	if (index >= arena->top)
   1042 		return NULL;
   1043 
   1044 	bitcast.in = arena->pages[pageindex] + pageoffset * arena->elemsize;
   1045 	return bitcast.out;
   1046 }
   1047 
   1048 static void
   1049 disposearena(MemArena *arena)
   1050 {
   1051 	int i;
   1052 	for (i = 0; i < arena->capacity; ++i) {
   1053 		if (arena->pages[i])
   1054 			free(arena->pages[i]);
   1055 		arena->pages[i] = NULL;
   1056 	}
   1057 	free(arena->pages);
   1058 	arena->pages = NULL;
   1059 }
   1060 
   1061 
   1062 
   1063 
   1064 // }}}
   1065 
   1066 // @section pre-lexer {{{
   1067 
   1068 static void
   1069 tryprompt(Source *source, const char ch);
   1070 
   1071 static bool
   1072 processcommand(Source *source);
   1073 
   1074 static bool
   1075 mygetline(Source *source)
   1076 {
   1077 	int i, l, c;
   1078 	FILE *in = source->filein;
   1079 
   1080 	tryprompt(source, '.');
   1081 	c = getc(in);
   1082 
   1083 	source->linepos = ftell(in);
   1084 
   1085 advance:
   1086 	++source->currloc.line;
   1087 
   1088 	i = 0, l = 0;
   1089 	while (c == '\r' || c == '\n') {
   1090 		tryprompt(source, '.');
   1091 		l = c, c = getc(in);
   1092 
   1093 		if (l == '\r' && c == '\n')
   1094 		       c = getc(in);
   1095 
   1096 		++source->currloc.line;
   1097 	}
   1098 
   1099 	source->tok.loc.line = source->currloc.line;
   1100 
   1101 	while (c != EOF && c != '\n' && c != '\r') {
   1102 		source->line[i++] = c;
   1103 		c = getc(in);
   1104 
   1105 		if (c == '\\') {
   1106 			int x = getc(in);
   1107 			if (x == '\n') {
   1108 				tryprompt(source, '\\');
   1109 				c = getc(in);
   1110 
   1111 				++source->currloc.line;
   1112 			} else if (x == '\r') {
   1113 				int y;
   1114 
   1115 				tryprompt(source, '\\');
   1116 				y = getc(in);
   1117 
   1118 				c = (y == '\n') ? getc(in) : y;
   1119 				++source->currloc.line;
   1120 			} else if (x == EOF) {
   1121 				c = x;
   1122 			} else {
   1123 				ungetc(x, in);
   1124 			}
   1125 		}
   1126 	}
   1127 
   1128 	if (c == '\r') {
   1129 		int x;
   1130 
   1131 		tryprompt(source, '.');
   1132 		x = getc(in);
   1133 		if (x != '\n')
   1134 			ungetc(x, in);
   1135 	}
   1136 
   1137 	if (c != EOF && i == 0)
   1138 		goto advance;
   1139 
   1140 	source->line[i] = 0;
   1141 
   1142 	if (in == stdin && source->line[0] == ':')
   1143 		return processcommand(source);
   1144 
   1145 	return c != EOF || i;
   1146 }
   1147 
   1148 
   1149 
   1150 // }}}
   1151 
   1152 // @section keyword map {{{
   1153 
   1154 #define KEYWORD_MAP_SIZE 128
   1155 const char *keywordkeys[KEYWORD_MAP_SIZE];
   1156 int keywordvals[KEYWORD_MAP_SIZE];
   1157 
   1158 static int
   1159 strnhash(const char *str, int n)
   1160 {
   1161 	int hash = 5381, i;
   1162 	for (i = 0; i < n && str[i]; ++i)
   1163 		hash = (hash << 5) + hash + str[i];
   1164 	return hash;
   1165 }
   1166 
   1167 static void
   1168 initkeywords(void)
   1169 {
   1170 	int i, j, h;
   1171 	for (i = 0; i < lengthof(keywordlengths); ++i) {
   1172 		int n = keywordlengths[i] = strlen(nodestrings[i + KSTART]);
   1173 		h = strnhash(nodestrings[i + KSTART], n) &
   1174 			(lengthof(keywordkeys) - 8);
   1175 		for (j = 0; j < 8; ++j, ++h) {
   1176 			if (!keywordkeys[h]) {
   1177 				keywordkeys[h] = nodestrings[i + KSTART];
   1178 				keywordvals[h] = i;
   1179 				goto nextkeyword;
   1180 			}
   1181 		}
   1182 
   1183 		fprintf(stderr, "bug: keyword hash-map is too small\n");
   1184 		abort();
   1185 	nextkeyword:
   1186 		(void) 0;
   1187 	}
   1188 
   1189 	/*
   1190 	for (i = 0; i < lengthof(keywordkeys); ++i) {
   1191 		printf("%-12s%c",
   1192 			keywordkeys[i] ? keywordkeys[i] : ".",
   1193 			(i+1) % 8 ? ' ' : '\n');
   1194 	}
   1195 	*/
   1196 }
   1197 
   1198 static int
   1199 getkeyword(const char *str, int n)
   1200 {
   1201 	int i, h = strnhash(str, n) & (lengthof(keywordkeys) - 8);
   1202 	for (i = 0; i < 8; ++i, ++h) {
   1203 		int len;
   1204 		if (!keywordkeys[h])
   1205 			return -1;
   1206 		len = keywordlengths[keywordvals[h]];
   1207 		if (n == len && memcmp(keywordkeys[h], str, n) == 0)
   1208 			return keywordvals[h];
   1209 	}
   1210 	return -1;
   1211 }
   1212 
   1213 
   1214 
   1215 // }}}
   1216 
   1217 // @section string map {{{
   1218 
   1219 typedef
   1220 struct StringEntry {
   1221 	int len;
   1222 	const char *str;
   1223 } StringEntry;
   1224 
   1225 typedef
   1226 struct StringMap {
   1227 	int *keys;
   1228 	int keyscap;
   1229 
   1230 	StringEntry *vals;
   1231 	int valscap, valslen;
   1232 } StringMap;
   1233 
   1234 StringMap idents;
   1235 StringMap strings;
   1236 
   1237 static void
   1238 initstrmap(StringMap *map)
   1239 {
   1240 	map->keys = calloc(32, sizeof(int));
   1241 	map->keyscap = 32;
   1242 	assert(map->keys);
   1243 
   1244 	map->vals = calloc(32, sizeof(StringEntry));
   1245 	map->valslen = 0;
   1246 	map->valscap = 32;
   1247 	assert(map->vals);
   1248 }
   1249 
   1250 #if 0
   1251 static void
   1252 disposestrmap(StringMap *map)
   1253 {
   1254 	int i;
   1255 	for (i = map->valslen - 1; i >= 0; --i) {
   1256 		free((char *) map->vals[i].str);
   1257 	}
   1258 
   1259 	free(map->vals);
   1260 	free(map->keys);
   1261 }
   1262 #endif
   1263 
   1264 static void
   1265 putstringkey(StringMap *map, int key, int hash)
   1266 {
   1267 	int *keys = map->keys;
   1268 	StringEntry *vals = map->vals;
   1269 
   1270 	int i, j;
   1271 
   1272 redo:
   1273 	j = (hash << 3) & (map->keyscap - 1);
   1274 	for (i = 0; i < 8; ++i, ++j) {
   1275 		if (!keys[j]) {
   1276 			keys[j] = key;
   1277 			return;
   1278 		}
   1279 	}
   1280 
   1281 	free(keys);
   1282 	map->keyscap *= 2;
   1283 	keys = map->keys = calloc(map->keyscap, sizeof(int));
   1284 	for (i = 0; i < map->valslen; ++i) {
   1285 		j = strnhash(vals[i].str, vals[i].len);
   1286 		putstringkey(map, i + 1, j);
   1287 	}
   1288 
   1289 	goto redo;
   1290 }
   1291 
   1292 int auxthen, auxin, auxto, auxstep;
   1293 int auxself;
   1294 
   1295 static int
   1296 getstringkey(StringMap *map, const char *str, int n)
   1297 {
   1298 	int *keys = map->keys;
   1299 	StringEntry *vals = map->vals;
   1300 
   1301 	int key, hash = strnhash(str, n);
   1302 	int i, j = (hash << 3) & (map->keyscap - 1);
   1303 
   1304 	char *newstr;
   1305 
   1306 	for (i = 0; i < 8; ++i, ++j) {
   1307 		key = keys[j];
   1308 		if (!key)
   1309 			break;
   1310 
   1311 		assert(key > 0);
   1312 		if (n == vals[key - 1].len &&
   1313 		    memcmp(str, vals[key - 1].str, n) == 0)
   1314 		{
   1315 			return key;
   1316 		}
   1317 	}
   1318 
   1319 	key = map->valslen + 1;
   1320 	putstringkey(map, key, hash);
   1321 
   1322 	if (key > map->valscap) {
   1323 		int cap = map->valscap * 3 / 2 + 1;
   1324 		vals = map->vals = realloc(vals, cap * sizeof(StringEntry));
   1325 		assert(vals);
   1326 		map->valscap = cap;
   1327 	}
   1328 
   1329 	/* @todo sizeof(char*) --> sizeof(char) ? */
   1330 	newstr = calloc(n + 1, sizeof(char*));
   1331 
   1332 	assert(newstr);
   1333 	memcpy(newstr, str, n);
   1334 
   1335 	vals[key - 1].len = n;
   1336 	vals[key - 1].str = newstr;
   1337 	++map->valslen;
   1338 
   1339 	return key;
   1340 }
   1341 
   1342 #define getstring(map, key) ((map).vals[(key) - 1].str)
   1343 #define getlength(map, key) ((map).vals[(key) - 1].len)
   1344 
   1345 
   1346 
   1347 // }}}
   1348 
   1349 // @section error reporting {{{
   1350 
   1351 int warningcount = 0;
   1352 int errorcount = 0;
   1353 
   1354 static int
   1355 warn(SrcLoc *loc, const char *fmt, ...)
   1356 {
   1357 	va_list ap;
   1358 	int n;
   1359 
   1360 	const char *filename = loc ? loc->filename : "<unknown-source>";
   1361 	uint line = loc ? loc->line : 1;
   1362 	uint column = loc ? loc->column : 0;
   1363 
   1364 	va_start(ap, fmt);
   1365 	n = fprintf(stderr, "%s:%u:%u: warning: ",
   1366 		filename, line, column + 1);
   1367 	n += vfprintf(stderr, fmt, ap);
   1368 	n += fprintf(stderr, "\n");
   1369 	va_end(ap);
   1370 
   1371 	++warningcount;
   1372 	return n;
   1373 }
   1374 
   1375 #define error(loc, ...) \
   1376 	error_(loc, __FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
   1377 
   1378 static int
   1379 error_(SrcLoc *loc, const char *func, const char *file, int line_,
   1380 	const char *fmt, ...)
   1381 {
   1382 	va_list ap;
   1383 	int n;
   1384 
   1385 	const char *filename = loc ? loc->filename : "<unknown-source>";
   1386 	uint line = loc ? loc->line : 1;
   1387 	uint column = loc ? loc->column : 0;
   1388 
   1389 	va_start(ap, fmt);
   1390 	n = fprintf(stderr, "%s:%u:%u: error: ",
   1391 		filename, line, column + 1);
   1392 	n += vfprintf(stderr, fmt, ap);
   1393 	n += fprintf(stderr, " \x1b[30m[in %s() at %s:%u]\x1b[0m\n",
   1394 		func, file, line_);
   1395 	va_end(ap);
   1396 
   1397 	++errorcount;
   1398 	return n;
   1399 }
   1400 
   1401 
   1402 
   1403 // }}}
   1404 
   1405 // @section lexer {{{
   1406 
   1407 #define nextindent(source, indent) \
   1408 	((indent) + (source)->tabwidth - ((indent) % (source)->tabwidth))
   1409 
   1410 #define peekchar(source) \
   1411 	((source)->line[(source)->currloc.column])
   1412 
   1413 #define peeknextchar(source) \
   1414 	((source)->line[(source)->currloc.column + 1])
   1415 
   1416 #define nextchar(source) \
   1417 	((source)->line[++(source)->currloc.column])
   1418 
   1419 // @sub-section tokenize keyword / identifier {{{
   1420 
   1421 static int
   1422 tokenizealphanumeric(Source *source, register int ch)
   1423 {
   1424 	int keyword;
   1425 
   1426 	while (isalnum(ch) || ch == '_')
   1427 		ch = nextchar(source);
   1428 
   1429 	keyword = getkeyword(
   1430 		source->line + source->tok.loc.column,
   1431 		source->currloc.column - source->tok.loc.column
   1432 	);
   1433 
   1434 	if (source->tok.kind != ANNOT && keyword >= 0 &&
   1435 	    source->tok.kind != ODISP)
   1436 	{
   1437 		if (keyword == KOR - KSTART || keyword == KAND - KSTART) {
   1438 			return source->tok.kind =
   1439 				keyword == KOR - KSTART ? OLOR : OLAND;
   1440 		} else if (keywordtypeids[keyword + KSTART]) {
   1441 
   1442 			source->tok.u.key =
   1443 				keywordtypeids[keyword + KSTART];
   1444 
   1445 			source->tok.type = prim + source->tok.u.key;
   1446 
   1447 			return source->tok.kind = TYPE;
   1448 		}
   1449 
   1450 		return source->tok.kind = keyword + KSTART;
   1451 	}
   1452 
   1453 	source->tok.u.key = getstringkey(
   1454 		&idents,
   1455 		source->line + source->tok.loc.column,
   1456 		source->currloc.column - source->tok.loc.column
   1457 	);
   1458 
   1459 	return source->tok.kind = IDENT;
   1460 }
   1461 
   1462 // }}}
   1463 
   1464 // @sub-section tokenize number {{{
   1465 
   1466 static Type *
   1467 suffixfloattype(Source *source, const char *end)
   1468 {
   1469 	Type *ty = primitive(TDOUBLE);
   1470 
   1471 	if (*end == 0)
   1472 		return ty;
   1473 
   1474 	/* FIXME(m21c): r-suffix might conflict with radix */
   1475 	if ((*end == 'f' || *end == 'F') && !end[1]) {
   1476 		ty = primitive(TFLOAT);
   1477 
   1478 	} else if (*end == 'l' || *end == 'L') {
   1479 		ty = primitive(TDOUBLE);
   1480 
   1481 		if (end[1])
   1482 			goto errorfloat;
   1483 
   1484 	} else if (!mystrcasecmp(end, "f32") || !mystrcasecmp(end, "r32")) {
   1485 		ty = primitive(TF32);
   1486 
   1487 	} else if (!mystrcasecmp(end, "f64") || !mystrcasecmp(end, "r64")) {
   1488 		ty = primitive(TF64);
   1489 
   1490 	} else {
   1491 	errorfloat:
   1492 		error(&source->currloc, "invalid floating-point format");
   1493 	}
   1494 
   1495 	return ty;
   1496 }
   1497 
   1498 static Type *
   1499 suffixinttype(Source *source, const char *end)
   1500 {
   1501 	int typeid = TUINT - TINT;
   1502 
   1503 	switch (*end) {
   1504 	case 0:
   1505 		return primitive(TINFER);
   1506 
   1507 	case 's': case 'S': case 'i': case 'I':
   1508 		typeid = 0;
   1509 
   1510 		/* fallthrough */
   1511 	case 'u': case 'U':
   1512 		++end;
   1513 		if (*end == 0) {
   1514 			return prim + (typeid + TINFER);
   1515 
   1516 		} else if (*end == '8') {
   1517 			typeid += TS8;
   1518 
   1519 			if (end[1])
   1520 				goto errorint;
   1521 
   1522 			return prim + typeid;
   1523 
   1524 		} else if (!strcmp(end, "16")) {
   1525 			return prim + (typeid + TS16);
   1526 
   1527 		} else if (!strcmp(end, "32")) {
   1528 			return prim + (typeid + TS32);
   1529 
   1530 		} else if (!strcmp(end, "64")) {
   1531 			return prim + (typeid + TS64);
   1532 
   1533 		} else if (!mystrcasecmp(end, "sz")) {
   1534 			return prim + (typeid + TSSIZE);
   1535 		}
   1536 
   1537 		/* fallthrough */
   1538 	default:
   1539 		if (!mystrcasecmp(end, "ll")) {
   1540 			return prim + (typeid + TLLONG);
   1541 
   1542 		} else if (*end == 'l' || *end == 'L') {
   1543 			typeid += TLONG;
   1544 
   1545 			if (end[1])
   1546 				goto errorint;
   1547 
   1548 			return prim + typeid;
   1549 		}
   1550 	}
   1551 
   1552 errorint:
   1553 	error(&source->currloc, "invalid integer format");
   1554 	return primitive(TINT);
   1555 }
   1556 
   1557 static int
   1558 tokenizenumber(Source *source, register int ch)
   1559 {
   1560 	int l = ch, t = peeknextchar(source), i, j;
   1561 	bool hasdec = false, hasexp = false;
   1562 	char *end;
   1563 
   1564 advancenum:
   1565 	while (isalnum(ch) || ch == '_' ||
   1566 	       (ch == '.' && peeknextchar(source) != '.' && !hasdec))
   1567 	{
   1568 		if (ch != '_')
   1569 			l = ch;
   1570 		if (ch == '.')
   1571 			hasdec = true;
   1572 
   1573 		ch = nextchar(source);
   1574 	}
   1575 
   1576 	if (hasdec && !hasexp && (ch == '+' || ch == '-')) {
   1577 		t = tolower(t);
   1578 		l = tolower(l);
   1579 
   1580 		if ((l == 'e' && t != 'x') || (l == 'p' && t == 'x')) {
   1581 			ch = nextchar(source);
   1582 			hasexp = true;
   1583 
   1584 			goto advancenum;
   1585 		}
   1586 	}
   1587 
   1588 	/* remove underscores */
   1589 	for (j = 0, i = source->tok.loc.column;
   1590 	     i < (int) source->currloc.column;
   1591 	     ++i)
   1592 	{
   1593 		if (source->line[i] != '_') {
   1594 			if (j >= lengthof(source->stringbuf) - 1) {
   1595 				error(
   1596 					&source->currloc,
   1597 					"number-literal is too long"
   1598 				);
   1599 
   1600 				source->tok.u.u = 0;
   1601 				source->tok.type = primitive(TINT);
   1602 
   1603 				return source->tok.kind = NUMBER;
   1604 			}
   1605 
   1606 			source->stringbuf[j++] = source->line[i];
   1607 		}
   1608 	}
   1609 	source->stringbuf[j] = 0;
   1610 
   1611 	if (strpbrk(source->stringbuf, ".pPrR") ||
   1612 	    (!strpbrk(source->stringbuf, "xX") &&
   1613 	    strpbrk(source->stringbuf, "eEfF")))
   1614 	{
   1615 		source->tok.u.d = strtod(source->stringbuf, &end);
   1616 		source->tok.type = suffixfloattype(source, end);
   1617 
   1618 	} else {
   1619 		if (mystrncasecmp(source->stringbuf, "0b", 2) == 0) {
   1620 			source->tok.u.u = strtoull(
   1621 				source->stringbuf + 2,
   1622 				&end, 2
   1623 			);
   1624 
   1625 		} else {
   1626 			source->tok.u.u = strtoull(
   1627 				source->stringbuf,
   1628 				&end, 0
   1629 			);
   1630 
   1631 		}
   1632 
   1633 		source->tok.type = suffixinttype(source, end);
   1634 	}
   1635 
   1636 	return source->tok.kind = NUMBER;
   1637 }
   1638 
   1639 // }}}
   1640 
   1641 // @sub-section tokenize string {{{
   1642 
   1643 static int
   1644 tokenizestring(Source *source, register int ch)
   1645 {
   1646 	int delim = ch, j;
   1647 
   1648 	ch = nextchar(source);
   1649 	source->tok.loc.column = source->currloc.column;
   1650 
   1651 	j = source->currloc.column;
   1652 	while (ch != delim && ch != 0) {
   1653 		if (ch == '\\') {
   1654 			ch = nextchar(source);
   1655 
   1656 			switch (ch) {
   1657 			case '\\':
   1658 				ch = '\\';
   1659 				break;
   1660 
   1661 			case 'n':
   1662 				ch = '\n';
   1663 				break;
   1664 
   1665 			case 'r':
   1666 				ch = '\r';
   1667 				break;
   1668 
   1669 			case 't':
   1670 				ch = '\t';
   1671 				break;
   1672 
   1673 			case '\'':
   1674 				ch = '\'';
   1675 				break;
   1676 
   1677 			case '"':
   1678 				ch = '"';
   1679 				break;
   1680 
   1681 			/* @todo read more escape sequences */
   1682 			case 0:
   1683 				goto stringeol;
   1684 
   1685 			default:
   1686 				error(&source->currloc,
   1687 					"invalid escape sequence '\\%c'", ch);
   1688 			}
   1689 		}
   1690 
   1691 		source->line[j++] = ch;
   1692 		ch = nextchar(source);
   1693 	}
   1694 
   1695 	++source->currloc.column;
   1696 	source->line[j++] = 0;
   1697 
   1698 	if (ch == 0) {
   1699 	stringeol:
   1700 		error(&source->currloc, "unexpected end-of-line");
   1701 
   1702 		return source->tok.kind = LINEDELIM;
   1703 	}
   1704 
   1705 	if (ch == '"') {
   1706 		source->tok.u.key = getstringkey(
   1707 			&strings,
   1708 			source->line + source->tok.loc.column,
   1709 			j - source->tok.loc.column
   1710 		);
   1711 
   1712 		return source->tok.kind = STRING;
   1713 	}
   1714 
   1715 	/* @todo read numerical value of character properly
   1716 	 *       (escape sequences, etc.) */
   1717 	source->tok.type = prim + TUCHAR;
   1718 	source->tok.u.u = source->line[source->tok.loc.column];
   1719 	return source->tok.kind = CHAR;
   1720 }
   1721 
   1722 // }}}
   1723 
   1724 // @sub-section tokenizer {{{
   1725 
   1726 static int
   1727 gettok(Source *source)
   1728 {
   1729 	register int ch = (uchar) peekchar(source);
   1730 
   1731 	source->lastkind = source->tok.kind;
   1732 
   1733 	if (source->savedtok.kind) {
   1734 		source->tok = source->savedtok;
   1735 		source->savedtok.kind = 0;
   1736 		return source->tok.kind;
   1737 	}
   1738 
   1739 skipwhite:
   1740 	if (source->hasnewline) {
   1741 		if (!mygetline(source)) {
   1742 			source->lastindent = 0;
   1743 			return source->tok.kind = 0;
   1744 		}
   1745 
   1746 		source->currloc.column = 0;
   1747 		ch = peekchar(source);
   1748 	}
   1749 
   1750 	if (source->currloc.column) {
   1751 		/* just skip whitespace */
   1752 		while (isspace(ch))
   1753 			ch = nextchar(source);
   1754 
   1755 	} else {
   1756 		/* skip whitespace and calculate indentation */
   1757 		source->lastindent = 0;
   1758 		while (isspace(ch)) {
   1759 			if (ch == '\t') {
   1760 				source->lastindent = nextindent(
   1761 					source,
   1762 					source->lastindent
   1763 				);
   1764 			} else {
   1765 				++source->lastindent;
   1766 			}
   1767 
   1768 			ch = nextchar(source);
   1769 		}
   1770 	}
   1771 
   1772 	source->tok.type = primitive(TUNDEFINED);
   1773 	source->tok.u.u = 0;
   1774 	source->tok.lhs = NULL;
   1775 	source->tok.rhs = NULL;
   1776 	source->tok.loc.column = source->currloc.column;
   1777 
   1778 	/* get line */
   1779 	if (!ch || ch == '#') {
   1780 		if (source->hasnewline) {
   1781 			goto skipwhite;
   1782 		} else {
   1783 			/* defer reading new line to next call of gettok()
   1784 			 * and return LINEDELIM */
   1785 			source->hasnewline = true;
   1786 			return source->tok.kind = LINEDELIM;
   1787 		}
   1788 	}
   1789 
   1790 	/* c-syle block comment with nesting allowed */
   1791 	if (ch == '/' && peeknextchar(source) == '*') {
   1792 		int nest = 1;
   1793 
   1794 		nextchar(source);
   1795 		ch = nextchar(source);
   1796 		
   1797 		for (;nest; ch = nextchar(source)) {
   1798 			if (!ch) {
   1799 				if (!mygetline(source))
   1800 					return source->tok.kind = 0;
   1801 
   1802 				/* is this needed? */
   1803 				source->currloc.column = 0;
   1804 				ch = peekchar(source);
   1805 			}
   1806 
   1807 			if (ch == '*' && peeknextchar(source) == '/') {
   1808 				nextchar(source);
   1809 				--nest;
   1810 			} else if (ch == '/' && peeknextchar(source) == '*') {
   1811 				nextchar(source);
   1812 				++nest;
   1813 			}
   1814 		}
   1815 
   1816 		goto skipwhite;
   1817 	}
   1818 
   1819 	source->hasnewline = false;
   1820 
   1821 	/* identifier or keyword */
   1822 	if (isalpha(ch) || ch == '_')
   1823 		return tokenizealphanumeric(source, ch);
   1824 
   1825 	/* number literal */
   1826 	if (isdigit(ch) || (ch == '.' && isdigit(peeknextchar(source))))
   1827 		return tokenizenumber(source, ch);
   1828 
   1829 	/* string & character-literal */
   1830 	if (ch == '"' || ch == '\'')
   1831 		return tokenizestring(source, ch);
   1832 
   1833 	/* operators */
   1834 #define select(ch, then, otherwise) ( \
   1835 		peekchar(source) == (ch) ? \
   1836 		++source->currloc.column, (then) : \
   1837 		(otherwise) \
   1838 	)
   1839 
   1840 	++source->currloc.column;
   1841 	switch (ch) {
   1842 	case '.':
   1843 		/* tok.kind = select('.', ORANGE, ODISP); */
   1844 		ch = ODISP;
   1845 		break;
   1846 
   1847 	case '*':
   1848 		ch = select('=', OMULA, OMUL);
   1849 		break;
   1850 
   1851 	case '/':
   1852 		ch = select('=', ODIVA, ODIV);
   1853 		break;
   1854 
   1855 	case '%':
   1856 		ch = select('=', OMODA, OMOD);
   1857 		break;
   1858 
   1859 	case '<':
   1860 		ch = select('=', OLEQ,
   1861 			select('<',
   1862 				select('=', OLSHA, OLSH),
   1863 			OLET));
   1864 		break;
   1865 
   1866 	case '>':
   1867 		ch = select('=', OGEQ,
   1868 			select('>',
   1869 				select('>',
   1870 					select('=', OARSHA, OARSH),
   1871 					select('=', ORSHA, ORSH)),
   1872 				OGRT));
   1873 		break;
   1874 
   1875 	case '&':
   1876 		ch = select('=', OANDA, select('&', OLAND, OBAND));
   1877 		break;
   1878 
   1879 	case '+':
   1880 		ch = select('=', OADDA, select('+', OSUFINC, OADD));
   1881 		break;
   1882 
   1883 	case '-':
   1884 		ch = select('=', OSUBA, select('-', OSUFDEC, OSUB));
   1885 		break;
   1886 
   1887 	case '|':
   1888 		ch = select('=', OORA, select('|', OLOR, OBOR));
   1889 		break;
   1890 
   1891 	case '^':
   1892 		ch = select('=', OXORA, OXOR);
   1893 		break;
   1894 
   1895 	case '!':
   1896 		ch = select('=', ONEQ, OLNOT);
   1897 		break;
   1898 
   1899 	case '~':
   1900 		ch = select('=', OFLIP, OBNOT);
   1901 		break;
   1902 
   1903 	case '=':
   1904 		ch = select('=', select('=', OIDENT, OEQU), OASS);
   1905 		break;
   1906 
   1907 	/* delimiters */
   1908 	case ',': ch = COMMADELIM; break;
   1909 	case ';': ch = SEMIDELIM;  break;
   1910 	case '@': ch = ANNOT;      break;
   1911 	case ':': ch = COLONDELIM; break;
   1912 	case '{': ch = LCURLDELIM; break;
   1913 	case '}': ch = RCURLDELIM; break;
   1914 	case '[': ch = LSQRDELIM;  break;
   1915 	case ']': ch = RSQRDELIM;  break;
   1916 	case '(': ch = LPARDELIM;  break;
   1917 	case ')': ch = RPARDELIM;  break;
   1918 
   1919 	default:
   1920 		error(&source->currloc, "invalid input character '%c'", ch);
   1921 		return INVALID;
   1922 	}
   1923 
   1924 	return source->tok.kind = ch;
   1925 #undef select
   1926 }
   1927 
   1928 // }}}
   1929 
   1930 // @sub-section tokenizer utilities {{{
   1931 
   1932 static void
   1933 pushbacktok(Source *source, Node *tok)
   1934 {
   1935 	assert(source->savedtok.kind == 0);
   1936 
   1937 	source->savedtok = source->tok;
   1938 	source->tok = *tok;
   1939 }
   1940 
   1941 #define skipnewline(source) \
   1942 	((source)->tok.kind == LINEDELIM ? (void) gettok(source) : (void) 0)
   1943 
   1944 static bool
   1945 isbasicdelimiter(Kind kind)
   1946 {
   1947 	switch ((int) kind) {
   1948 	case 0:
   1949 	case LINEDELIM: case COMMADELIM: case SEMIDELIM:
   1950 	case COLONDELIM:
   1951 	case RPARDELIM: case RSQRDELIM: case RCURLDELIM:
   1952 	case KELSE:
   1953 	case KUNTIL:
   1954 		return true;
   1955 	}
   1956 
   1957 	return false;
   1958 }
   1959 
   1960 static Kind
   1961 getunary(Kind kind)
   1962 {
   1963 	if (getprec(kind) == PUNARY)
   1964 		return kind;
   1965 
   1966 	switch (kind) {
   1967 	case OMUL: return ODEREF;
   1968 	case OBAND: return OADDR;
   1969 	case OADD: return OPLUS;
   1970 	case OSUB: return OMINUS;
   1971 	case OSUFINC: return OINC;
   1972 	case OSUFDEC: return ODEC;
   1973 	default:
   1974 		return 0;
   1975 	}
   1976 }
   1977 
   1978 static bool
   1979 isdelimiter(Kind kind)
   1980 {
   1981 	if (isbasicdelimiter(kind))
   1982 		return true;
   1983 
   1984 	if (getunary(kind))
   1985 		return false;
   1986 
   1987 	if (getnumops(kind))
   1988 		return true;
   1989 
   1990 	return false;
   1991 }
   1992 
   1993 static Kind
   1994 getunarysuffix(Source *source)
   1995 {
   1996 	Kind kind = source->tok.kind;
   1997 
   1998 	if (getprec(kind) == PUNSUF)
   1999 		return kind;
   2000 
   2001 	/* @note fixes parsing unary suffix across multiple lines.
   2002 	 *              (which shouldn't happen) */
   2003 	if (isbasicdelimiter(source->lastkind) && kind != COLONDELIM)
   2004 		return 0;
   2005 
   2006 	switch (kind) {
   2007 	case COLONDELIM: return ASELFDISP;
   2008 	case LPARDELIM: return OCALL;
   2009 	case LSQRDELIM: return OARRAY;
   2010 	default:
   2011 		return 0;
   2012 	}
   2013 }
   2014 
   2015 // }}}
   2016 
   2017 
   2018 
   2019 // }}}
   2020 
   2021 // @section ast-node {{{
   2022 
   2023 Node *poolednodes;
   2024 int poolednodecount, totalnodecount;
   2025 
   2026 #define tokennode(source, lhs) \
   2027 	makenode(&(source)->arenas, &(source)->tok, (lhs))
   2028 
   2029 static Node *
   2030 makenode(SourceArenas *arenas, Node *orig, Node *lhs)
   2031 {
   2032 	Node *node;
   2033 
   2034 	if (poolednodes) {
   2035 		node = poolednodes;
   2036 		poolednodes = poolednodes->rhs;
   2037 		node->rhs = NULL;
   2038 		node->lhs = NULL;
   2039 		--poolednodecount;
   2040 	} else {
   2041 		node = myalloc(&arenas->node, Node);
   2042 	}
   2043 
   2044 	++totalnodecount;
   2045 	*node = *orig;
   2046 	node->lhs = lhs;
   2047 	node->rhs = NULL;
   2048 
   2049 	return node;
   2050 }
   2051 
   2052 static void
   2053 deleteenv(Env *env);
   2054 
   2055 static void
   2056 deletenode(Node *node)
   2057 {
   2058 	if (node->kind == 0)
   2059 		return;
   2060 
   2061 	if (node->kind == ASCOPE) {
   2062 		Node *curr, *next;
   2063 
   2064 		if (node->u.env) {
   2065 			assert(node->u.env->stmts == node);
   2066 			node->u.env->stmts = NULL;
   2067 			deleteenv(node->u.env);
   2068 		}
   2069 
   2070 		for (curr = node->lhs; curr; curr = next) {
   2071 			assert(curr->kind == ASTMT);
   2072 			next = curr->rhs;
   2073 			deletenode(curr);
   2074 		}
   2075 
   2076 	} else if (node->kind == ASTMT) {
   2077 		if (node->lhs)
   2078 			deletenode(node->lhs);
   2079 
   2080 	} else {
   2081 		if (node->rhs)
   2082 			deletenode(node->rhs);
   2083 
   2084 		if (node->lhs)
   2085 			deletenode(node->lhs);
   2086 
   2087 		if (node->u.payload && (node->kind == KIF ||
   2088 		    node->kind == KWHILE || node->kind == ALOOPUNTIL))
   2089 		{
   2090 			deletenode(node->u.payload);
   2091 		}
   2092 	}
   2093 
   2094 	++poolednodecount;
   2095 	node->kind = 0;
   2096 	node->rhs = poolednodes;
   2097 	poolednodes = node;
   2098 }
   2099 
   2100 
   2101 
   2102 // }}}
   2103 
   2104 // @section type-struct {{{
   2105 
   2106 static Type *
   2107 maketype(SourceArenas *arenas, SrcLoc *loc, Type *orig, Type *target)
   2108 {
   2109 	Type *ty = myalloc(&arenas->type, Type);
   2110 
   2111 	*ty = *orig;
   2112 	ty->loc = *loc;
   2113 	ty->target = target;
   2114 
   2115 	return ty;
   2116 }
   2117 
   2118 
   2119 
   2120 // }}}
   2121 
   2122 // @section annotation {{{
   2123 
   2124 static Annot *
   2125 makeannot(SourceArenas *arenas, SrcLoc *loc, int key)
   2126 {
   2127 	Annot *annot = myalloc(&arenas->annot, Annot);
   2128 
   2129 	annot->key = key;
   2130 	annot->loc = *loc;
   2131 
   2132 	/* @todo implement initialization. */
   2133 
   2134 	return annot;
   2135 }
   2136 
   2137 static Docket *
   2138 makedocket(SourceArenas *arenas, Node *node)
   2139 {
   2140 	Docket *docket = myalloc(&arenas->docket, Docket);
   2141 
   2142 	(void) node; /* @todo implement. */
   2143 
   2144 	/* @todo implement initialization. */
   2145 
   2146 	return docket;
   2147 }
   2148 
   2149 
   2150 
   2151 // }}}
   2152 
   2153 // @section environment {{{
   2154 
   2155 static Decl *
   2156 finddeclinenv(int key, Env *env)
   2157 {
   2158 	const int cacheindex = (key >> 3) & 0x3f;
   2159 	const int cachebit = 1 << (key & 0x03);
   2160 
   2161 	Decl *decl;
   2162 
   2163 	if ((env->keycache[cacheindex] & cachebit) == 0)
   2164 		return NULL;
   2165 
   2166 	for (decl = env->head; decl; decl = decl->next) {
   2167 		if (decl->key == key)
   2168 			return decl;
   2169 	}
   2170 
   2171 	return NULL;
   2172 }
   2173 
   2174 static Decl *
   2175 finddeclaration(Source *source, Env *startenv, int key)
   2176 {
   2177 	const int cacheindex = (key >> 3) & 0x3f;
   2178 	const int cachebit = 1 << (key & 0x03);
   2179 
   2180 	Env *env;
   2181 	Decl *decl;
   2182 
   2183 	for (env = startenv; env; env = env->below) {
   2184 		/* @note look-up exclusion list first.
   2185 		 *              If found: only lookup in found env */
   2186 		/* FIXME(m21c): make a separate list, and not use excludehead,
   2187 		 *               excludenext ! */
   2188 		/*
   2189 		for (decl = env->excludehead; decl; decl = decl->excludenext) {
   2190 			if (decl->key == key)
   2191 				return finddeclinenv(key, env);
   2192 		}
   2193 		*/
   2194 
   2195 
   2196 		if ((env->keycache[cacheindex] & cachebit) == 0)
   2197 			continue;
   2198 
   2199 		for (decl = env->head; decl; decl = decl->next) {
   2200 			if (decl->key == key)
   2201 				return decl;
   2202 		}
   2203 	}
   2204 
   2205 	if (!source)
   2206 		return NULL;
   2207 
   2208 	env = source->implicitenv;
   2209 
   2210 	if ((env->keycache[cacheindex] & cachebit) == 0)
   2211 		return NULL;
   2212 
   2213 	for (decl = env->head; decl; decl = decl->next) {
   2214 		if (decl->key == key)
   2215 			return decl;
   2216 	}
   2217 
   2218 	return NULL;
   2219 }
   2220 
   2221 #if 0
   2222 static Env *
   2223 setheadenv(Source *source, EnvKind kind)
   2224 {
   2225 	/* @note this might only be useful for parameter => function env
   2226 	 *              translation */
   2227 	Env *env = myalloc(&source->arenas.env, Env);
   2228 
   2229 	env->kind = kind;
   2230 
   2231 	/* @todo make sure that source->tok.loc is the correct
   2232 	 *              source-location. */
   2233 	/* @todo maybe use getloc(source) instead of
   2234 	 *              &source->tok.loc and move the declaration of
   2235 	 *              getloc() up in the source-code. */
   2236 	env->loc = source->tok.loc;
   2237 	env->below = source->currenv;
   2238 
   2239 	assert(source->headenv == NULL);
   2240 	env->arenas = &source->arenas;
   2241 	source->currenv = source->headenv = env;
   2242 
   2243 	return env;
   2244 }
   2245 #endif
   2246 
   2247 static Env *
   2248 pushenv(Source *source, EnvKind kind)
   2249 {
   2250 	Env *env;
   2251 
   2252 	if (source->headenv) {
   2253 		source->headenv->kind = kind;
   2254 
   2255 		assert(source->headenv == source->currenv);
   2256 		source->headenv = NULL;
   2257 
   2258 		return source->currenv;
   2259 	}
   2260 
   2261 	env = myalloc(&source->arenas.env, Env);
   2262 	env->kind = kind;
   2263 	/* @todo make sure that source->tok.loc is the correct
   2264 	 *              source-location. */
   2265 	/* @todo maybe use getloc(source) instead of
   2266 	 *              &source->tok.loc and move the declaration of
   2267 	 *              getloc() up in the source-code. */
   2268 	env->loc = source->tok.loc;
   2269 	env->below = source->currenv;
   2270 
   2271 	env->arenas = &source->arenas;
   2272 	source->currenv = env;
   2273 
   2274 	return env;
   2275 }
   2276 
   2277 static Env *
   2278 popenv(Source *source)
   2279 {
   2280 	Env *currenv = source->currenv;
   2281 	Env *env = currenv;
   2282 
   2283 	if (currenv)
   2284 		source->currenv = currenv->below;
   2285 
   2286 	return env;
   2287 }
   2288 
   2289 static Env *
   2290 getfuncenv(Env *currenv)
   2291 {
   2292 	Env *env;
   2293 
   2294 	for (env = currenv; env; env = env->below) {
   2295 		if (env->kind == SFUNCTION) {
   2296 			return env;
   2297 		}
   2298 	}
   2299 
   2300 	return NULL;
   2301 }
   2302 
   2303 static bool
   2304 deferfuncenv(Source *source, int keydeclinfunc)
   2305 {
   2306 	Env *funcenv = getfuncenv(source->currenv);
   2307 
   2308 	if (funcenv) {
   2309 		if (!funcenv->pending) {
   2310 			funcenv->pending = true;
   2311 			/* @todo handle nested functions properly */
   2312 			source->haspendingenv = true;
   2313 
   2314 			listappendex(source, funcenv,
   2315 				pendingenvhead, pendingenvtail,
   2316 				pendingprev, pendingnext);
   2317 		}
   2318 	} else {
   2319 		/* @todo maybe use getloc(source) instead of
   2320 		 *              &source->tok.loc and move the declaration of
   2321 		 *              getloc() up in the source-code. */
   2322 		error(
   2323 			&source->tok.loc,
   2324 			"'%s' undeclared",
   2325 			getstring(idents, keydeclinfunc)
   2326 		);
   2327 
   2328 		return false;
   2329 	}
   2330 
   2331 	return true;
   2332 }
   2333 
   2334 
   2335 static Node *
   2336 wrapenv(Node *node, Env *env)
   2337 {
   2338 	Node *aenv = makenode(env->arenas, node, node);
   2339 
   2340 	aenv->kind = AENV;
   2341 	aenv->u.env = env;
   2342 
   2343 	return aenv;
   2344 }
   2345 
   2346 static void
   2347 deleteenv(Env *env)
   2348 {
   2349 	if (env->stmts)
   2350 		deletenode(env->stmts);
   2351 
   2352 	/* @todo delete env */
   2353 }
   2354 
   2355 static bool
   2356 isrecordenv(Env *env)
   2357 {
   2358 	assert(env);
   2359 	return env->kind == SSTRUCT || env->kind == SUNION;
   2360 }
   2361 
   2362 
   2363 
   2364 // }}}
   2365 
   2366 // @section declaration {{{
   2367 
   2368 static void
   2369 appenddecltoenv(Decl *decl, Env *targetenv)
   2370 {
   2371 	const int key = decl->key;
   2372 	const int cacheindex = (key >> 3) & 0x3f;
   2373 	const int cachebit = 1 << (key & 0x03);
   2374 
   2375 	targetenv->keycache[cacheindex] |= cachebit;
   2376 
   2377 	decl->parentenv = targetenv;
   2378 
   2379 	listappend(targetenv, decl);
   2380 }
   2381 
   2382 static void
   2383 removedeclfromenv(Decl *decl)
   2384 {
   2385 	Env *sourceenv = decl->parentenv;
   2386 
   2387 	if (decl->prev)
   2388 		decl->prev->next = decl->next;
   2389 	else
   2390 		sourceenv->head = decl->next;
   2391 
   2392 	if (decl->next)
   2393 		decl->next->prev = decl->prev;
   2394 	else
   2395 		sourceenv->tail = decl->prev;
   2396 
   2397 	decl->parentenv = NULL;
   2398 	decl->next = decl->prev = NULL;
   2399 }
   2400 
   2401 static Decl *
   2402 makedecl(Source *source, int key, DeclKind kind)
   2403 {
   2404 	Env *currenv = source->currenv;
   2405 	Decl *decl;
   2406 
   2407 	assert(currenv);
   2408 
   2409 	/* @todo maybe remove check if already declared,
   2410 	 *              since many functions that call makedecl
   2411 	 *              already try to obtain a declaration for
   2412 	 *              other reasons. So the check if it is
   2413 	 *              already declared can be done by those
   2414 	 *              functions */
   2415 
   2416 	decl = finddeclinenv(key, currenv);
   2417 
   2418 	if (decl) {
   2419 		if (decl->parentenv == source->implicitenv) {
   2420 			removedeclfromenv(decl);
   2421 			appenddecltoenv(decl, currenv);
   2422 
   2423 			return decl;
   2424 		}
   2425 
   2426 		/* @todo make sure that source->tok.loc is the correct
   2427 		*              source-location. */
   2428 		/* @todo maybe use getloc(source) instead of
   2429 		 *              &source->tok.loc and move the declaration of
   2430 		 *              getloc() up in the source-code. */
   2431 		error(
   2432 			&source->tok.loc,
   2433 			"'%s' already declared",
   2434 			getstring(idents, key)
   2435 		);
   2436 	}
   2437 
   2438 	decl = myalloc(&source->arenas.decl, Decl);
   2439 
   2440 	decl->kind = kind;
   2441 	/* @todo make sure that source->tok.loc is the correct
   2442 	 *              source-location. */
   2443 	/* @todo maybe use getloc(source) instead of
   2444 	 *              &source->tok.loc and move the declaration of
   2445 	 *              getloc() up in the source-code. */
   2446 	decl->loc = source->tok.loc;
   2447 	decl->key = key;
   2448 	decl->type = primitive(TVOID);
   2449 	decl->contentenv = NULL;
   2450 	decl->module = NULL;
   2451 
   2452 	appenddecltoenv(decl, currenv);
   2453 
   2454 	return decl;
   2455 }
   2456 
   2457 static Decl *
   2458 makebundle(Source *source, int key, Decl *parentbundle)
   2459 {
   2460 	/* Env *currenv = source->currenv; */
   2461 	Decl *decl;
   2462 
   2463 	/* assert(currenv); */
   2464 
   2465 	decl = myalloc(&source->arenas.decl, Decl);
   2466 
   2467 	decl->kind = DBUNDLE;
   2468 	/* @todo make sure that source->tok.loc is the correct
   2469 	 *              source-location. */
   2470 	/* @todo maybe use getloc(source) instead of
   2471 	 *              &source->tok.loc and move the declaration of
   2472 	 *              getloc() up in the source-code. */
   2473 	decl->loc = source->tok.loc;
   2474 	decl->key = key;
   2475 	decl->type = primitive(TVOID);
   2476 	decl->contentenv = NULL;
   2477 	decl->module = parentbundle;
   2478 
   2479 	return decl;
   2480 }
   2481 
   2482 static Decl *
   2483 makedecl2(SrcLoc *loc, Env *env, int key, DeclKind kind)
   2484 {
   2485 	Decl *decl;
   2486 
   2487 	assert(env);
   2488 
   2489 	/* @todo maybe remove check if already declared,
   2490 	 *              since many functions that call makedecl
   2491 	 *              already try to obtain a declaration for
   2492 	 *              other reasons. So the check if it is
   2493 	 *              already declared can be done by those
   2494 	 *              functions */
   2495 
   2496 	decl = finddeclinenv(key, env);
   2497 	if (decl) {
   2498 		/* @todo maybe check also for implicit declarations */
   2499 		error(loc, "'%s' already declared", getstring(idents, key));
   2500 	}
   2501 
   2502 	decl = myalloc(&env->arenas->decl, Decl);
   2503 
   2504 	decl->kind = kind;
   2505 	/* @todo make sure that source->tok.loc is the correct
   2506 	 *              source-location. */
   2507 	/* @todo maybe use getloc(source) instead of
   2508 	 *              &source->tok.loc and move the declaration of
   2509 	 *              getloc() up in the source-code. */
   2510 	decl->loc = *loc;
   2511 	decl->key = key;
   2512 	decl->type = primitive(TVOID);
   2513 	decl->contentenv = NULL;
   2514 
   2515 	appenddecltoenv(decl, env);
   2516 
   2517 	return decl;
   2518 }
   2519 
   2520 static Decl *
   2521 defertypedeclaration(Source *source, int key)
   2522 {
   2523 	Env *savedcurrenv = source->currenv;
   2524 	Decl *decl;
   2525 
   2526 	source->currenv = source->implicitenv;
   2527 	decl = makedecl(source, key, DTYPE);
   2528 
   2529 	/* FIXME(m21c): type may be overwritten, when the declaration
   2530 	 *               is completed */
   2531 	decl->type = maketype(
   2532 		&source->arenas, &source->tok.loc, primitive(TVOID), NULL);
   2533 	decl->type->module = decl;
   2534 	source->currenv = savedcurrenv;
   2535 
   2536 	return decl;
   2537 }
   2538 
   2539 
   2540 
   2541 // }}}
   2542 
   2543 // @section record {{{
   2544 
   2545 static Record *
   2546 makerecord(Source *source, Decl *recorddecl)
   2547 {
   2548 	Record *record = myalloc(&source->arenas.record, Record);
   2549 	
   2550 	record->head = record->tail = NULL;
   2551 
   2552 	recorddecl->record = record;
   2553 
   2554 	assert(recorddecl->type);
   2555 	record->isunion = recorddecl->type->kind == TUNION;
   2556 
   2557 	return record;
   2558 }
   2559 
   2560 static Field *
   2561 makefield(Source *source, Record *record, Decl *decl)
   2562 {
   2563 	Field *field = myalloc(&source->arenas.field, Field);
   2564 	
   2565 	field->decl = decl;
   2566 	field->offset = field->size = 0;
   2567 	field->use = false;
   2568 	field->prev = field->next = NULL;
   2569 
   2570 	assert(record);
   2571 	listappend(record, field);
   2572 
   2573 	return field;
   2574 }
   2575 
   2576 
   2577 
   2578 // }}}
   2579 
   2580 // @section parser {{{
   2581 
   2582 #define getkind(source) \
   2583 	((source)->tok.kind)
   2584 
   2585 #define getloc(source) \
   2586 	(&(source)->tok.loc)
   2587 
   2588 static bool
   2589 expect(Source *source, int kind, const char *fmt, ...)
   2590 {
   2591 	va_list ap;
   2592 
   2593 	int line = source->tok.loc.line;
   2594 	int column = source->tok.loc.column;
   2595 	const char *filename = source->tok.loc.filename;
   2596 
   2597 	if (getkind(source) != (Kind) kind) {
   2598 		va_start(ap, fmt);
   2599 		fprintf(stderr, "%s:%i:%i: error: ",
   2600 			filename, line, column + 1);
   2601 		vfprintf(stderr, fmt, ap);
   2602 		fprintf(stderr, "\n");
   2603 		va_end(ap);
   2604 
   2605 		return false;
   2606 	}
   2607 
   2608 	gettok(source);
   2609 	return true;
   2610 }
   2611 
   2612 // @sub-section read annotations {{{
   2613 
   2614 static AnnotParam *
   2615 readannotparam(Source *source)
   2616 {
   2617 	bool hasident = false;
   2618 
   2619 	while (getkind(source)) {
   2620 		int count = 1;
   2621 
   2622 		switch (getkind(source)) {
   2623 		case IDENT:
   2624 			if (!hasident) {
   2625 				int key = source->tok.u.key;
   2626 				const char *ident = getstring(idents, key);
   2627 				printf("Annotation Parameter: %s\n", ident);
   2628 
   2629 				hasident = true;
   2630 			}
   2631 
   2632 			gettok(source);
   2633 			break;
   2634 
   2635 		case COMMADELIM: case RPARDELIM:
   2636 			goto finish;
   2637 
   2638 		case LPARDELIM:
   2639 			gettok(source);
   2640 			while (getkind(source) && count > 0) {
   2641 				switch (getkind(source)) {
   2642 				case LPARDELIM:
   2643 					++count;
   2644 					break;
   2645 				case RPARDELIM:
   2646 					--count;
   2647 					break;
   2648 				default:
   2649 					break;
   2650 				}
   2651 				gettok(source);
   2652 			}
   2653 
   2654 			if(!getkind(source))
   2655 				goto finish;
   2656 
   2657 			/* FALLTHROUGH */
   2658 		default:
   2659 			gettok(source);
   2660 		}
   2661 	}
   2662 
   2663 finish:
   2664 	return NULL;
   2665 }
   2666 
   2667 static void
   2668 readannots(Source *source)
   2669 {
   2670 	Docket *docket = NULL;
   2671 
   2672 	while (getkind(source) == ANNOT) {
   2673 		SrcLoc loc = source->tok.loc;
   2674 		int key = 0;
   2675 
   2676 		Annot *annot = NULL;
   2677 
   2678 		gettok(source);
   2679 
   2680 		key = source->tok.u.key;
   2681 		if (!expect(source, IDENT, "expected annotation-identifier."))
   2682 			return;
   2683 
   2684 		annot = makeannot(&source->arenas, &loc, key);
   2685 
   2686 		if (getkind(source) == LPARDELIM) {
   2687 			int count;
   2688 
   2689 			gettok(source);
   2690 			for (count = 0; getkind(source); ++count) {
   2691 				AnnotParam *param = readannotparam(source);
   2692 
   2693 				if (param)
   2694 					listappend(annot, param);
   2695 
   2696 				if (getkind(source) == COMMADELIM) {
   2697 					gettok(source);
   2698 					continue;
   2699 				}
   2700 
   2701 				if (getkind(source) != RPARDELIM) {
   2702 					error(getloc(source),
   2703 						"expected ',' or ')'.");
   2704 				} else {
   2705 					gettok(source);
   2706 				}
   2707 
   2708 				break;
   2709 			}
   2710 		}
   2711 
   2712 		if (docket == NULL) {
   2713 			docket = makedocket(&source->arenas, NULL);
   2714 			/* @todo add docket to source */
   2715 		}
   2716 
   2717 		listappend(docket, annot);
   2718 
   2719 		skipnewline(source);
   2720 
   2721 		printf("Annotation: '%s'\n", getstring(idents, key));
   2722 	}
   2723 }
   2724 
   2725 // }}}
   2726 
   2727 // @sub-section read statement list {{{
   2728 
   2729 static bool
   2730 checkend(Source *source, bool hastail, int needindent,
   2731 		const char *expecterrmsg)
   2732 {
   2733 	Node savedtok = {0};
   2734 
   2735 	if (getkind(source) == LINEDELIM) {
   2736 		savedtok = source->tok;
   2737 
   2738 		gettok(source);
   2739 
   2740 		if (getkind(source) == SEMIDELIM) {
   2741 			error(getloc(source), expecterrmsg);
   2742 			gettok(source);
   2743 
   2744 			pushbacktok(source, &savedtok);
   2745 			return true;
   2746 		}
   2747 	}
   2748 
   2749 	if (source->lastkind == LINEDELIM && source->lastindent < needindent) {
   2750 		/* @note Is that correct? Maybe we should always pushback
   2751 		 *              a made-up new-line, instead of asserting that we
   2752 		 *              have saved one. Since it might be the case, that
   2753 		 *              we already have read a new-line prior the call
   2754 		 *              to this function. But I'll leave it this way,
   2755 		 *              for now. */
   2756 		/* assert(savedtok.kind == LINEDELIM); */
   2757 
   2758 		if (savedtok.kind == LINEDELIM)
   2759 			pushbacktok(source, &savedtok);
   2760 		return true;
   2761 	}
   2762 
   2763 	if (getkind(source) == SEMIDELIM) {
   2764 		savedtok = source->tok;
   2765 		gettok(source);
   2766 
   2767 		/* @note used for REPL. it allows having
   2768 		 *              semicolons on line-endings and nultiple
   2769 		 *              adjacent semecolons in REPL-mode. */
   2770 		if ((getkind(source) == SEMIDELIM ||
   2771 		     getkind(source) == LINEDELIM) &&
   2772 		    source->filein != stdin)
   2773 			/* @note output an error-message if not in REPL-mode */
   2774 			error(&savedtok.loc, "trailing semicolon.");
   2775 	}
   2776 
   2777 	if (isdelimiter(source->tok.kind))
   2778 		return true;
   2779 
   2780 	if (hastail &&
   2781 	    source->lastkind != LINEDELIM &&
   2782 	    source->lastkind != SEMIDELIM)
   2783 		error(getloc(source), "expected line delimiter");
   2784 
   2785 	return false;
   2786 }
   2787 
   2788 static Node *
   2789 exprlist(Source *source, bool isparam, Type *paramtype);
   2790 
   2791 static Node *
   2792 stmtlist(Source *source, int indent, EnvKind envkind,
   2793 		Decl *envdecl, bool reuseenv)
   2794 {
   2795 	Node *head = NULL, *tail = NULL;
   2796 	int needindent = nextindent(source, indent);
   2797 
   2798 	Env *env = NULL;
   2799 
   2800 	if (reuseenv) {
   2801 		source->currenv->kind = envkind;
   2802 	} else {
   2803 		env = pushenv(source, envkind);
   2804 		env->envdecl = envdecl;
   2805 	}
   2806 
   2807 	for (;;) {
   2808 		Node *stmt;
   2809 
   2810 		if (checkend(source, !!tail, needindent, "expected expression"))
   2811 			break;
   2812 
   2813 		if (getkind(source) == LINEDELIM)
   2814 			gettok(source);
   2815 
   2816 		readannots(source);
   2817 		stmt = exprlist(source, false, NULL);
   2818 		stmt = tokennode(source, stmt);
   2819 		stmt->kind = ASTMT;
   2820 
   2821 		if (!tail) {
   2822 			head = tail = stmt;
   2823 		} else {
   2824 			tail->rhs = stmt;
   2825 			tail = stmt;
   2826 		}
   2827 	}
   2828 
   2829 	if (reuseenv) {
   2830 		assert(env == NULL);
   2831 		env = source->currenv;
   2832 	}
   2833 
   2834 	if (head) {
   2835 		head = tokennode(source, head);
   2836 		head->kind = ASCOPE;
   2837 		head->u.env = env;
   2838 		env->stmts = head;
   2839 
   2840 		popenv(source);
   2841 	} else {
   2842 		popenv(source);
   2843 		/* if (!reuseenv) deleteenv(env); */
   2844 	}
   2845 
   2846 	return head;
   2847 }
   2848 
   2849 // }}}
   2850 
   2851 // @sub-section read declaration {{{
   2852 
   2853 static int
   2854 qualifiers(Source *source, int allowmask)
   2855 {
   2856 	int flags = 0, mask = allowmask;
   2857 
   2858 	while (iskeyword(getkind(source))) {
   2859 		int f, m;
   2860 
   2861 		switch (getkind(source)) {
   2862 		case KEXTERN:
   2863 			f = QEXTERN, m = ~QVISIB;
   2864 			break;
   2865 
   2866 		case KINTERN:
   2867 			f = QINTERN, m = ~QVISIB;
   2868 			break;
   2869 
   2870 		case KSTATIC:
   2871 			f = QSTATIC, m = ~QSTORAGE;
   2872 			break;
   2873 
   2874 		case KCONST:
   2875 			f = QCONST, m = 0;
   2876 			break;
   2877 
   2878 		/* @todo remove this */
   2879 		case KVAR:
   2880 			f = QVAR, m = ~(QTYPE | QINFER);
   2881 			break;
   2882 
   2883 		default:
   2884 			goto finish;
   2885 		}
   2886 
   2887 		if (f & ~allowmask) {
   2888 			const char *str = nodestrings[getkind(source)];
   2889 
   2890 			error(getloc(source), "invalid qualifier '%s'", str);
   2891 		} else if (f & flags & QTYPE) {
   2892 			const char *str = nodestrings[getkind(source)];
   2893 
   2894 			warn(getloc(source), "redundant qualifier '%s'", str);
   2895 		} else if (f & ~mask) {
   2896 			const char *str = nodestrings[getkind(source)];
   2897 
   2898 			error(getloc(source), "redundant qualifier '%s'", str);
   2899 		}
   2900 
   2901 		flags |= f & allowmask & mask;
   2902 		mask &= m;
   2903 		gettok(source);
   2904 	}
   2905 
   2906 finish:
   2907 	return flags;
   2908 }
   2909 
   2910 static Node *
   2911 readexpr(Source *source, int minprec);
   2912 
   2913 static Type *
   2914 gettype(Source *source, Type *basetype)
   2915 {
   2916 	int flags;
   2917 
   2918 	if (!basetype)
   2919 		return NULL;
   2920 
   2921 advance:
   2922 	flags = qualifiers(source, QTYPE);
   2923 	(void) flags;
   2924 
   2925 	if (getkind(source) == LSQRDELIM) {
   2926 		Type *tmp = maketype(
   2927 			&source->arenas, getloc(source),
   2928 			primitive(TARRAY), basetype);
   2929 		basetype = tmp;
   2930 
   2931 		gettok(source);
   2932 		if (source->tok.kind != RSQRDELIM)
   2933 			basetype->u.val = readexpr(source, PASSIGN);
   2934 
   2935 		expect(source, RSQRDELIM, "expect ']'");
   2936 		goto advance;
   2937 	}
   2938 
   2939 	if (getkind(source) == OMUL) {
   2940 		Type *tmp = maketype(
   2941 			&source->arenas, getloc(source),
   2942 			primitive(TPTR), basetype);
   2943 		basetype = tmp;
   2944 
   2945 		gettok(source);
   2946 		goto advance;
   2947 	}
   2948 
   2949 	return basetype;
   2950 }
   2951 
   2952 static Node *
   2953 typecheck(Env *env, Node *expr);
   2954 
   2955 static Node *
   2956 declaration(Source *source, Type *ty, bool tryreadtype)
   2957 {
   2958 	bool selfparam = false;
   2959 	Type *module = NULL;
   2960 	Decl *decl = NULL;
   2961 	Node *result = NULL;
   2962 
   2963 	Env *env = source->currenv;
   2964 
   2965 	/*
   2966 	EnvKind context;
   2967 	*/
   2968 
   2969 	if (tryreadtype) {
   2970 		decl = finddeclaration(
   2971 			source, env, source->tok.u.key);
   2972 
   2973 		if (decl && decl->kind == DTYPE) {
   2974 			gettok(source);
   2975 			ty = gettype(source, decl->type);
   2976 			tryreadtype = false;
   2977 		}
   2978 	}
   2979 
   2980 	if (!ty)
   2981 		return NULL;
   2982 
   2983 	/* @todo use the currenv->kind as context, whether or how
   2984 	 *              certain declarations (like function-declarations)
   2985 	 *              are processed */
   2986 
   2987 	/*
   2988 	context = env->kind;
   2989 	*/
   2990 
   2991 redodeclaration:
   2992 	skipnewline(source);
   2993 
   2994 	/* variable name */
   2995 	if (getkind(source) == IDENT) {
   2996 		int key = source->tok.u.key;
   2997 		SrcLoc loc = source->tok.loc;
   2998 
   2999 		gettok(source);
   3000 
   3001 		if (tryreadtype && isrecordenv(env)) {
   3002 
   3003 			if (!isbasicdelimiter(getkind(source)) &&
   3004 			    getkind(source) != LPARDELIM)
   3005 			{
   3006 				decl = defertypedeclaration(source, key);
   3007 				decl->loc = loc;
   3008 				ty = gettype(source, decl->type);
   3009 				tryreadtype = false;
   3010 				goto redodeclaration;
   3011 			}
   3012 		}
   3013 
   3014 		decl = finddeclaration(source, env, key);
   3015 
   3016 		if (decl && decl->kind != DFUNCTION && decl->kind != DPARAM &&
   3017 		    decl->kind != DVAR)
   3018 		{
   3019 			module = decl->type;
   3020 			decl = NULL;
   3021 			goto readvarmodule;
   3022 		}
   3023 
   3024 		if ((getkind(source) == ODISP || getkind(source) == COLONDELIM)
   3025 		&&   getkind(source) != LPARDELIM && getkind(source) != OASS)
   3026 		{
   3027 			error(&loc, "expected type or module");
   3028 		}
   3029 
   3030 		decl = makedecl(source, key, DVAR);
   3031 		decl->loc = loc;
   3032 		decl->type = ty;
   3033 
   3034 	/* module for variable */
   3035 	} else if (getkind(source) == TYPE) {
   3036 		module = source->tok.type;
   3037 		gettok(source);
   3038 
   3039 	readvarmodule:
   3040 		module = gettype(source, module);
   3041 
   3042 		if (getkind(source) == ODISP || getkind(source) == COLONDELIM) {
   3043 			selfparam = getkind(source) == COLONDELIM;
   3044 			(void) selfparam;
   3045 			gettok(source);
   3046 		} else {
   3047 			error(getloc(source), "expected '.' or ':'");
   3048 		}
   3049 
   3050 		/* @todo obtain Decl* for
   3051 		 *              Type Module:my_decl
   3052 		 *              or Type Module.my_decl - declarations */
   3053 
   3054 		/* variable name */
   3055 		if (getkind(source) == IDENT) {
   3056 			Env *moduleenv = NULL;
   3057 			assert(module->module);
   3058 			assert(module->module->contentenv);
   3059 			moduleenv = module->module->contentenv;
   3060 
   3061 			decl = makedecl2(&source->tok.loc, 
   3062 				moduleenv, source->tok.u.key, DVAR);
   3063 			decl->type = ty;
   3064 			decl->module = module->module;
   3065 			gettok(source);
   3066 		} else {
   3067 			error(getloc(source), "expected identifier");
   3068 		}
   3069 	/* just return a node for the type */
   3070 	} else {
   3071 		result = tokennode(source, NULL);
   3072 		result->kind = TYPE;
   3073 		result->type = ty;
   3074 
   3075 		return result;
   3076 	}
   3077 
   3078 	if (!decl->module)
   3079 		decl->module = env->bundle;
   3080 
   3081 	/* function declaration */
   3082 	if (getkind(source) == LPARDELIM) {
   3083 		Type *paramtype = NULL;
   3084 		Env *functionenv = NULL;
   3085 		Node *body = NULL;
   3086 
   3087 		/* function params */
   3088 		gettok(source);
   3089 		if (getkind(source) != RPARDELIM) {
   3090 			Decl *param;
   3091 			Node *paramlist;
   3092 			Type *paramtype = NULL;
   3093 
   3094 			functionenv = pushenv(source, SPARAMLIST);
   3095 			functionenv->envdecl = decl;
   3096 
   3097 			if (selfparam) {
   3098 				param = makedecl(source, auxself, DVAR);
   3099 				param->type = maketype(
   3100 					&source->arenas, &param->loc,
   3101 					prim + TPTR, module);
   3102 				param->flags |= MSPECIAL;
   3103 				/* @note param doesn't need to be added to
   3104 				 *       paramlist. since paramlist will be 
   3105 				 *       deleted anyway and param is already
   3106 				 *       present in env. */
   3107 				paramtype = param->type;
   3108 			}
   3109 
   3110 			paramlist = exprlist(source, true, paramtype);
   3111 			paramlist = typecheck(functionenv, paramlist);
   3112 			paramtype = paramlist->type;
   3113 			deletenode(paramlist);
   3114 
   3115 			for (param = functionenv->head; param;
   3116 			     param = param->next)
   3117 			{
   3118 				assert(param->kind == DVAR);
   3119 				param->kind = DPARAM;
   3120 			}
   3121 		} else if (selfparam) {
   3122 			Type *selftype = maketype(&source->arenas, &decl->loc,
   3123 				primitive(TPTR), module);
   3124 			Decl *selfdecl;
   3125 			
   3126 			functionenv = pushenv(source, SPARAMLIST);
   3127 			functionenv->envdecl = decl;
   3128 
   3129 			selfdecl = makedecl(source, auxself, DPARAM);
   3130 			selfdecl->type = selftype;
   3131 			selfdecl->flags |= MSPECIAL;
   3132 		}
   3133 		expect(source, RPARDELIM, "expected ')'");
   3134 
   3135 		if (module && ty->kind == TINFER) {
   3136 			ty = module;
   3137 		} else if (ty->kind == TINFER) {
   3138 			error(&decl->loc,
   3139 				"cannot infer return type of function");
   3140 		}
   3141 
   3142 		decl->type = maketype(
   3143 			&source->arenas, &decl->loc,
   3144 			primitive(TFUNCTION), paramtype);
   3145 		decl->kind = DFUNCTION;
   3146 		decl->type->u.rtarget = ty;
   3147 		ty = decl->type;
   3148 
   3149 		/* function body */
   3150 		if (getkind(source) != OASS) {
   3151 			body = stmtlist(source, source->lastindent,
   3152 				SFUNCTION, decl, !!functionenv);
   3153 
   3154 			if (!isrecordenv(env)) {
   3155 				assert(body && body->kind == ASCOPE);
   3156 				functionenv = body->u.env;
   3157 			}
   3158 
   3159 		/* function init (body defined by assigment) */
   3160 		} else if (getkind(source) == OASS) {
   3161 			gettok(source);
   3162 
   3163 			functionenv->kind = SFUNCTION;
   3164 			body = readexpr(source, PASSIGN);
   3165 
   3166 			popenv(source);
   3167 
   3168 		/* no function body */
   3169 		} else {
   3170 			popenv(source);
   3171 		}
   3172 
   3173 		assert(decl->contentenv == NULL);
   3174 		decl->contentenv = functionenv;
   3175 
   3176 		assert(decl->u.content == NULL);
   3177 		decl->u.content = body;
   3178 
   3179 
   3180 		/* @todo maybe add function-declaration to its type and
   3181 		 *              add the paramlist to the type-info */
   3182 
   3183 		/* @todo store the params-node (its initializations)
   3184 		 *              somewhere */
   3185 
   3186 		goto finish;
   3187 	}
   3188 
   3189 	/* variable init */
   3190 	if (getkind(source) == OASS) {
   3191 		gettok(source);
   3192 		assert(decl);
   3193 		decl->u.content = readexpr(source, PASSIGN);
   3194 
   3195 	/* no init */
   3196 	} else {
   3197 		assert(decl);
   3198 		decl->u.content = NULL;
   3199 
   3200 		if (ty->kind == TINFER) {
   3201 			error(&decl->loc,
   3202 				"cannot infer type, expected initialization");
   3203 		}
   3204 	}
   3205 
   3206 finish:
   3207 	if (isrecordenv(env))
   3208 		decl->flags |= MRECORDMEMBER;
   3209 
   3210 	result = tokennode(source, decl->u.content);
   3211 	result->type = ty;
   3212 	result->u.declref = decl;
   3213 	result->loc = decl->loc;
   3214 	result->kind = ADECL;
   3215 
   3216 	return result;
   3217 }
   3218 
   3219 // }}}
   3220 
   3221 // @sub-section read atom {{{
   3222 
   3223 static Node *
   3224 readident(Source *source, int flags)
   3225 {
   3226 	Node *lhs = NULL;
   3227 	Decl *decl = NULL;
   3228 	SrcLoc loc = source->tok.loc;
   3229 	int key = source->tok.u.key;
   3230 
   3231 	decl = finddeclaration(source, source->currenv, source->tok.u.key);
   3232 	gettok(source);
   3233 
   3234 	if (!decl && isrecordenv(source->currenv)) {
   3235 		if (!isbasicdelimiter(getkind(source))) {
   3236 			decl = defertypedeclaration(source, key);
   3237 			decl->loc = loc;
   3238 		}
   3239 	}
   3240 
   3241 	if (decl && decl->kind == DTYPE) {
   3242 		lhs = declaration(source, gettype(source, decl->type), false);
   3243 		return lhs;
   3244 	}
   3245 
   3246 	lhs = tokennode(source, NULL);
   3247 	lhs->loc = loc;
   3248 
   3249 	if (decl) {
   3250 		lhs->kind = ADECLREF;
   3251 		lhs->type = decl->type;
   3252 		lhs->u.declref = decl;
   3253 	} else {
   3254 		if (deferfuncenv(source, key)) {
   3255 			lhs->kind = IDENT;
   3256 			lhs->u.key = key;
   3257 		} else {
   3258 			lhs->kind = NUMBER;
   3259 			lhs->u.u = 0;
   3260 		}
   3261 
   3262 		lhs->type = primitive(TVOID);
   3263 	}
   3264 
   3265 	if (flags & QCONST) {
   3266 		/* @todo const - conversion */
   3267 	}
   3268 
   3269 	return lhs;
   3270 }
   3271 
   3272 static void
   3273 extractfields(Source *source, Record *record, Node *recordscope)
   3274 {
   3275 	Node *stmt;
   3276 
   3277 	for (stmt = recordscope->lhs; stmt; stmt = stmt->rhs) {
   3278 		Node *expr;
   3279 
   3280 		assert(stmt->kind == ASTMT);
   3281 
   3282 		expr = stmt->lhs;
   3283 
   3284 		/* @fixme expr might be validly NULL */
   3285 		assert(expr);
   3286 
   3287 		if (expr->kind == ACOMMA) {
   3288 			for (; expr; expr = expr->lhs) {
   3289 				Node *nested;
   3290 
   3291 				if (expr->kind == ADECL)
   3292 					makefield(
   3293 						source, record, expr->u.declref);
   3294 
   3295 				if (expr->kind != ACOMMA)
   3296 					break;
   3297 
   3298 				nested = expr->rhs;
   3299 
   3300 				if (nested->kind != ADECL)
   3301 					continue;
   3302 
   3303 				makefield(source, record, nested->u.declref);
   3304 			}
   3305 			continue;
   3306 		}
   3307 		if (expr->kind != ADECL)
   3308 			continue;
   3309 
   3310 		makefield(source, record, expr->u.declref);
   3311 	}
   3312 }
   3313 
   3314 static void
   3315 calculatefields(Record *record, Type *recordtype)
   3316 {
   3317 	const bool isunion = record->isunion;
   3318 	Field *field;
   3319 
   3320 	/* @todo calculate size/align for unions */
   3321 	for (field = record->head; field; field = field->next) {
   3322 		size_t mod = 0, padding;
   3323 		Type *type;
   3324 
   3325 		type = field->decl->type;
   3326 
   3327 		if (recordtype->align < type->align)
   3328 			recordtype->align = type->align;
   3329 
   3330 		if (isunion) {
   3331 			if (recordtype->size < type->size)
   3332 				recordtype->size = type->size;
   3333 			continue;
   3334 		}
   3335 
   3336 		if (recordtype->align)
   3337 			mod = recordtype->size % recordtype->align;
   3338 
   3339 		padding = mod ? recordtype->align - mod : 0;
   3340 		field->offset = padding + recordtype->size;
   3341 		recordtype->size += padding + type->size;
   3342 	}
   3343 }
   3344 
   3345 static Node *
   3346 readrecord(Source *source, bool isunion)
   3347 {
   3348 	Node *recordnode;
   3349 	Decl *module;
   3350 	Record *record;
   3351 	int indent = source->lastindent;
   3352 
   3353 	EnvKind envkind = SSTRUCT;
   3354 	TypeKind typekind = TSTRUCT;
   3355 
   3356 	if (isunion) {
   3357 		envkind = SUNION;
   3358 		typekind = TUNION;
   3359 	}
   3360 
   3361 	recordnode = tokennode(source, NULL);
   3362 	recordnode->kind = getkind(source);
   3363 	gettok(source);
   3364 
   3365 	/* read record tag-name */
   3366 	if (getkind(source) == IDENT) {
   3367 		recordnode->lhs = tokennode(source, NULL);
   3368 		gettok(source);
   3369 	} else {
   3370 		recordnode->lhs = tokennode(source, NULL);
   3371 		recordnode->kind = 0;
   3372 		error(getloc(source), "expected identifier");
   3373 	}
   3374 
   3375 	module = makedecl(source, recordnode->lhs->u.key, DTYPE);
   3376 
   3377 	if (module->type->module == module) {
   3378 		*module->type = prim[TSTRUCT];
   3379 	} else {
   3380 		module->type = maketype(
   3381 			&source->arenas, &recordnode->loc,
   3382 			prim + typekind, NULL);
   3383 	}
   3384 
   3385 	module->type->module = module;
   3386 	recordnode->type = module->type;
   3387 
   3388 	if (!module->module) /* @note currently module->module == NULL always */
   3389 		module->module = source->currenv->bundle;
   3390 
   3391 	/* read record body */
   3392 
   3393 	/* @note maybe we will use stmtlist() for parsing the record body,
   3394 	                since we have to parse statements or expressions beside
   3395 	                field declarations */
   3396 
   3397 	/* @todo check for new-line and only then read body */
   3398 	module->contentenv = pushenv(source, envkind);
   3399 	module->contentenv->envdecl = module;
   3400 	recordnode->rhs = stmtlist(source, indent, envkind, module, true);
   3401 
   3402 	record = makerecord(source, module);
   3403 
   3404 	/* @todo validate record body, extract declarations,
   3405 	 *              compute size and align, resolve aliases */
   3406 
   3407 	if (recordnode->rhs) {
   3408 		assert(recordnode->rhs->kind == ASCOPE);
   3409 		extractfields(source, record, recordnode->rhs);
   3410 	}
   3411 
   3412 	calculatefields(record, recordnode->type);
   3413 	return recordnode;
   3414 }
   3415 
   3416 static bool
   3417 skipnewlineontok(Source *source, Kind kind, int neededindent)
   3418 {
   3419 	Node savedtok;
   3420 
   3421 	if (getkind(source) == kind)
   3422 		return source->lastindent >= neededindent;
   3423 
   3424 	if (getkind(source) == LINEDELIM) {
   3425 		savedtok = source->tok;
   3426 
   3427 		if (gettok(source) == (int) kind &&
   3428 		    source->lastindent >= neededindent)
   3429 			return true;
   3430 
   3431 		pushbacktok(source, &savedtok);
   3432 	}
   3433 
   3434 	return false;
   3435 }
   3436 
   3437 static Node *
   3438 readrecordinitfield(Source *source, Type *recordtype)
   3439 {
   3440 	Node *fieldinit = NULL;
   3441 	Node savedtok = {0};
   3442 
   3443 	/* @todo add init-env */
   3444 
   3445 	skipnewline(source);
   3446 
   3447 	fieldinit = tokennode(source, NULL);
   3448 	fieldinit->kind = AFIELDINIT;
   3449 	if (getkind(source) == IDENT) {
   3450 		savedtok = source->tok;
   3451 		gettok(source);
   3452 		if (getkind(source) == COLONDELIM) {
   3453 			gettok(source);
   3454 			/* @todo associate field name with field in record
   3455 			 *       type */
   3456 			fieldinit->lhs = makenode(
   3457 				&source->arenas, &savedtok, NULL);
   3458 		} else {
   3459 			pushbacktok(source, &savedtok);
   3460 		}
   3461 	}
   3462 
   3463 	fieldinit->rhs = readexpr(source, PASSIGN);
   3464 	return fieldinit;
   3465 }
   3466 
   3467 static Node *
   3468 readrecordinitfieldlist(Source *source, Type *recordtype)
   3469 {
   3470 	/* @todo add init-env */
   3471 	/* @todo check for missing field-initializers */
   3472 	Node *init = readrecordinitfield(source, recordtype);
   3473 
   3474 	while (skipnewline(source), getkind(source) == COMMADELIM) {
   3475 		init = tokennode(source, init);
   3476 		init->kind = ACOMMA;
   3477 		gettok(source);
   3478 		init->rhs = readrecordinitfield(source, recordtype);
   3479 	}
   3480 
   3481 	return init;
   3482 }
   3483 
   3484 static Node *
   3485 finishcontrolflow(Source *source, Node *lhs, int indent)
   3486 {
   3487 	if (skipnewlineontok(source, KELSE, indent)) {
   3488 		gettok(source);
   3489 		lhs->rhs = stmtlist(source, indent, SELSE, NULL, false);
   3490 	}
   3491 
   3492 	return wrapenv(lhs, popenv(source));
   3493 }
   3494 
   3495 static Node *
   3496 readatom(Source *source, int flags)
   3497 {
   3498 	Node *lhs = NULL, *savedis = source->lastis;
   3499 	int indent;
   3500 
   3501 	/* unary 'is'-operator */
   3502 	if (getkind(source) == KIS) {
   3503 		if (!source->lastis) {
   3504 			error(
   3505 				getloc(source),
   3506 				"there is no left-hand-side for 'is'"
   3507 			);
   3508 
   3509 			lhs = tokennode(source, NULL);
   3510 		} else {
   3511 			lhs = tokennode(source, source->lastis->lhs);
   3512 		}
   3513 
   3514 		gettok(source);
   3515 
   3516 		if (getkind(source) == KNOT)
   3517 			gettok(source), lhs->kind = ONEQ;
   3518 		else
   3519 			lhs->kind = OEQU;
   3520 
   3521 		lhs->rhs = readexpr(source, PRELAT);
   3522 		return lhs;
   3523 	}
   3524 
   3525 	/* unary prefix operators */
   3526 	if (getunary(source->tok.kind)) {
   3527 		lhs = tokennode(source, NULL);
   3528 
   3529 		/* @todo remove redundant function-call */
   3530 		lhs->kind = getunary(source->tok.kind);
   3531 
   3532 		gettok(source);
   3533 		lhs->lhs = readatom(source, 0);
   3534 		return lhs;
   3535 	}
   3536 
   3537 	if (flags & ~(QINFER | QCONST)) {
   3538 		error(getloc(source), "invalid use of qualifiers");
   3539 		flags = flags & (QINFER | QCONST);
   3540 	}
   3541 
   3542 	if (flags) {
   3543 		lhs = readatom(source, flags);
   3544 		return lhs;
   3545 	}
   3546 
   3547 	/* actual atom */
   3548 	switch (getkind(source)) {
   3549 	case LPARDELIM:
   3550 		gettok(source);
   3551 
   3552 		if (getkind(source) == LINEDELIM) {
   3553 			/* FIXME(m21c): stmtlist should ignore indentation in
   3554 			 *               this case! */
   3555 			lhs = stmtlist(source, source->lastindent,
   3556 					SSCOPE, NULL, false);
   3557 			source->lastis = savedis;
   3558 		} else {
   3559 			lhs = exprlist(source, false, NULL);
   3560 			source->lastis = savedis;
   3561 
   3562 			if (lhs->kind == TYPE) {
   3563 				/* @note expecting that the type is also set in
   3564 				 *       lhs->type */
   3565 				lhs->kind = OCAST;
   3566 				skipnewline(source);
   3567 				expect(source, RPARDELIM, "expected ')'");
   3568 
   3569 				lhs->lhs = readatom(source, 0);
   3570 				break;
   3571 			}
   3572 
   3573 			if (lhs->kind == ACOMMA &&
   3574 			    lhs->lhs->kind == TYPE &&
   3575 			    lhs->rhs->kind == TYPE)
   3576 			{
   3577 				Type *ty = maketype(
   3578 					&source->arenas, &lhs->loc,
   3579 					primitive(TTUPLE), NULL);
   3580 				ty->target = lhs->lhs->type;
   3581 				ty->u.rtarget = lhs->rhs->type;
   3582 				deletenode(lhs);
   3583 
   3584 				skipnewline(source);
   3585 				expect(source, RPARDELIM, "expected ')'");
   3586 
   3587 				lhs = declaration(source,
   3588 					gettype(source, ty), false);
   3589 
   3590 				assert(lhs);
   3591 				return lhs;
   3592 			}
   3593 
   3594 			skipnewline(source);
   3595 		}
   3596 
   3597 		expect(source, RPARDELIM, "expected ')'");
   3598 		break;
   3599 
   3600 	case IDENT:
   3601 		lhs = readident(source, flags);
   3602 		break;
   3603 
   3604 	case TYPE:
   3605 		do {
   3606 			Type *type = source->tok.type;
   3607 			gettok(source);
   3608 			lhs = declaration(source, gettype(source, type), false);
   3609 		} while (0);
   3610 
   3611 		break;
   3612 
   3613 	case NUMBER:
   3614 	case STRING:
   3615 	case CHAR:
   3616 		lhs = tokennode(source, NULL);
   3617 		gettok(source);
   3618 
   3619 		if (flags & QCONST) {
   3620 			/* @todo const - conversion */
   3621 		}
   3622 
   3623 		break;
   3624 
   3625 	case KVAR:
   3626 		gettok(source);
   3627 		lhs = declaration(source, primitive(TINFER), false);
   3628 		/* skip postfix-operators */
   3629 		return lhs;
   3630 
   3631 	case KFALSE:
   3632 	case KTRUE:
   3633 		lhs = tokennode(source, NULL);
   3634 		lhs->kind = NUMBER;
   3635 		lhs->type = primitive(TBOOL);
   3636 		lhs->u.u = (uintmax_t) (getkind(source) == KTRUE);
   3637 		gettok(source);
   3638 		break;
   3639 
   3640 	case KNULL:
   3641 		lhs = tokennode(source, NULL);
   3642 		lhs->kind = NUMBER;
   3643 		lhs->type = maketype(
   3644 			&source->arenas, &source->tok.loc,
   3645 			primitive(TPTR), primitive(TVOID));
   3646 		lhs->u.u = (uintmax_t) (getkind(source) == KTRUE);
   3647 		gettok(source);
   3648 		break;
   3649 
   3650 	case KSTRUCT:
   3651 	case KUNION:
   3652 		lhs = readrecord(source, source->tok.kind == KUNION);
   3653 		/* skip postfix-operators */
   3654 		return lhs;
   3655 
   3656 	case KNOT:
   3657 		lhs = tokennode(source, NULL);
   3658 		gettok(source);
   3659 		lhs->kind = OLNOT;
   3660 		lhs->lhs = readexpr(source, PRELAT);
   3661 		break;
   3662 
   3663 	case KALIGNOF:
   3664 	case KSIZEOF:
   3665 	case KLENGTHOF:
   3666 		lhs = tokennode(source, NULL);
   3667 		gettok(source);
   3668 		if (getkind(source) == LPARDELIM) {
   3669 			gettok(source);
   3670 			lhs->lhs = exprlist(source, false, NULL);
   3671 			expect(source, RPARDELIM, "expected ')'");
   3672 		} else {
   3673 			lhs->lhs = readatom(source, 0);
   3674 		}
   3675 
   3676 		break;
   3677 
   3678 	case KBITCAST:
   3679 		lhs = tokennode(source, NULL);
   3680 		gettok(source);
   3681 		expect(source, LPARDELIM, "expected '('");
   3682 		lhs->rhs = exprlist(source, false, NULL);
   3683 		expect(source, RPARDELIM, "expected ')'");
   3684 		lhs->lhs = readatom(source, 0);
   3685 		break;
   3686 
   3687 	case KBREAK:
   3688 	case KCONTINUE:
   3689 		lhs = tokennode(source, NULL);
   3690 		lhs->kind = getkind(source);
   3691 		gettok(source);
   3692 
   3693 		if (getkind(source) == COLONDELIM) {
   3694 			gettok(source);
   3695 			skipnewline(source);
   3696 			if (getkind(source) == IDENT) {
   3697 				lhs->lhs = tokennode(source, NULL);
   3698 				gettok(source);
   3699 			} else {
   3700 				error(getloc(source), "expected identifier");
   3701 			}
   3702 		}
   3703 
   3704 		break;
   3705 
   3706 	case KRETURN:
   3707 		lhs = tokennode(source, NULL);
   3708 		gettok(source);
   3709 
   3710 		if (getkind(source) == COLONDELIM) {
   3711 			gettok(source);
   3712 			skipnewline(source);
   3713 			if (getkind(source) == IDENT) {
   3714 				lhs->lhs = tokennode(source, NULL);
   3715 				gettok(source);
   3716 			} else {
   3717 				error(getloc(source), "expected identifier");
   3718 			}
   3719 		}
   3720 
   3721 		/* if is atom */
   3722 		if (!isdelimiter(source->tok.kind))
   3723 			lhs->rhs = exprlist(source, false, NULL);
   3724 
   3725 		break;
   3726 
   3727 	case KDO:
   3728 		indent = source->lastindent;
   3729 		lhs = tokennode(source, NULL);
   3730 		gettok(source);
   3731 		lhs->lhs = stmtlist(source, indent, SDO, NULL, false);
   3732 		/* skip postfix-operators */
   3733 		return lhs;
   3734 
   3735 	case KLOOP:
   3736 		indent = source->lastindent;
   3737 		lhs = tokennode(source, NULL);
   3738 		gettok(source);
   3739 		pushenv(source, SLOOPHEADER);
   3740 		lhs->lhs = stmtlist(source, indent, SLOOP, NULL, false);
   3741 
   3742 		if (skipnewlineontok(source, KUNTIL, indent)) {
   3743 			lhs->kind = ALOOPUNTIL;
   3744 			gettok(source);
   3745 			lhs->u.payload = readexpr(source, POR);
   3746 		}
   3747 
   3748 		if (lhs->kind != KLOOP)
   3749 			goto joinelse;
   3750 		
   3751 		/* skip postfix-operators */
   3752 		//	return finishcontrolflow(source, lhs, indent);
   3753 
   3754 		return wrapenv(lhs, popenv(source));
   3755 
   3756 	case KFOR:
   3757 		indent = source->lastindent;
   3758 		lhs = tokennode(source, NULL);
   3759 		gettok(source);
   3760 		
   3761 		pushenv(source, SLOOPHEADER);
   3762 		lhs->u.payload = readexpr(source, POR);
   3763 		if (getkind(source) == IDENT) {
   3764 			if (source->tok.u.key == auxin) {
   3765 				Node *aux = tokennode(source, NULL);
   3766 				aux->lhs = lhs->u.payload;
   3767 				aux->kind = AFOREACH;
   3768 				lhs->u.payload = aux;
   3769 				gettok(source);
   3770 				aux->rhs = readexpr(source, POR);
   3771 			} else if (source->tok.u.key == auxto) {
   3772 				Node *aux = tokennode(source, NULL);
   3773 				aux->lhs = lhs->u.payload;
   3774 				aux->kind = AFORSTEP;
   3775 				lhs->u.payload = aux;
   3776 				gettok(source);
   3777 				aux->rhs = readexpr(source, POR);
   3778 				if (getkind(source) == IDENT
   3779 				&&  source->tok.u.key == auxstep) {
   3780 					gettok(source);
   3781 					aux->u.payload = readexpr(source, POR);
   3782 				} else {
   3783 					aux->u.payload = tokennode(source, NULL);
   3784 					aux->u.payload->kind = NUMBER;
   3785 					aux->u.payload->type = primitive(TINFER);
   3786 					aux->u.payload->u.s = 1;
   3787 				}
   3788 			} else if (source->tok.u.key == auxstep) {
   3789 				Node *aux = tokennode(source, NULL);
   3790 				aux->lhs = lhs->u.payload;
   3791 				aux->kind = AFORSTEP;
   3792 				lhs->u.payload = aux;
   3793 				gettok(source);
   3794 				aux->u.payload = readexpr(source, POR);
   3795 
   3796 				/* @note is this even correct? */
   3797 				aux->rhs = tokennode(source, NULL);
   3798 				aux->rhs->kind = NUMBER;
   3799 				aux->rhs->type = primitive(TINFER);
   3800 				aux->rhs->u.s = INTMAX_MAX;
   3801 			}
   3802 		}
   3803 
   3804 		/* @todo maybe use SFOR instead of SLOOP */
   3805 		lhs->lhs = stmtlist(source, indent, SLOOP, NULL, false);
   3806 		goto joinelse;
   3807 		return finishcontrolflow(source, lhs, indent);
   3808 
   3809 	case KWHILE:
   3810 		indent = source->lastindent;
   3811 		lhs = tokennode(source, NULL);
   3812 		gettok(source);
   3813 		pushenv(source, SLOOPHEADER);
   3814 		lhs->u.payload = readexpr(source, POR);
   3815 		lhs->lhs = stmtlist(source, indent, SWHILE, NULL, false);
   3816 		goto joinelse;
   3817 		return finishcontrolflow(source, lhs, indent);
   3818 
   3819 	case KIF:
   3820 		indent = source->lastindent;
   3821 		lhs = tokennode(source, NULL);
   3822 		gettok(source);
   3823 		pushenv(source, SIFHEADER);
   3824 		lhs->u.payload = readexpr(source, POR);
   3825 		/* skipnewline(source); */
   3826 
   3827 		if (getkind(source) == IDENT && source->tok.u.key == auxthen)
   3828 			gettok(source);
   3829 
   3830 		lhs->lhs = stmtlist(source, indent, SIF, NULL, false);
   3831 	joinelse:
   3832 		if (skipnewlineontok(source, KELSE, indent)) {
   3833 			gettok(source);
   3834 			lhs->rhs = stmtlist(source, indent, SELSE, NULL, false);
   3835 		}
   3836 		return finishcontrolflow(source, lhs, indent);
   3837 
   3838 		/* skip postfix-operators */
   3839 		return wrapenv(lhs, popenv(source));
   3840 
   3841 	case LINEDELIM:
   3842 		/* @note is looping needed? */
   3843 		while (getkind(source) == LINEDELIM)
   3844 			gettok(source);
   3845 		return readatom(source, flags);
   3846 
   3847 	default:
   3848 	/* joinerror: */
   3849 		error(getloc(source), "expected expression");
   3850 		lhs = tokennode(source, NULL);
   3851 		lhs->kind = NUMBER;
   3852 		lhs->type = primitive(TERRTYPE);
   3853 		lhs->u.u = 0;
   3854 		gettok(source);
   3855 	}
   3856 
   3857 	/* compound-literal */
   3858 	if (getkind(source) == LCURLDELIM && lhs->kind == TYPE) {
   3859 		lhs = tokennode(source, lhs);
   3860 		lhs->kind = ACOMPOUND;
   3861 		lhs->type = lhs->lhs->type;
   3862 
   3863 		gettok(source);
   3864 		// source->lastindent = nextindent(source, source->lastindent);
   3865 		lhs->rhs = readrecordinitfieldlist(source, lhs->type);
   3866 		expect(source, RCURLDELIM, "expected '}'");
   3867 	}
   3868 
   3869 	/* unary postfix operators */
   3870 	while (getunarysuffix(source)) {
   3871 		lhs = tokennode(source, lhs);
   3872 
   3873 		/* @todo remove redundant function-call */
   3874 		lhs->kind = getunarysuffix(source);
   3875 
   3876 		if (getkind(source) == ODISP) {
   3877 			gettok(source);
   3878 			skipnewline(source);
   3879 
   3880 			if (getkind(source) != IDENT)
   3881 				error(getloc(source), "expected identifier");
   3882 
   3883 			lhs->rhs = tokennode(source, NULL);
   3884 
   3885 		} else if (getkind(source) == COLONDELIM) {
   3886 			gettok(source);
   3887 			skipnewline(source);
   3888 
   3889 			if (getkind(source) != IDENT)
   3890 				error(getloc(source), "expected identifier");
   3891 
   3892 			lhs->rhs = tokennode(source, NULL);
   3893 
   3894 		} else if (getkind(source) == LPARDELIM) {
   3895 			gettok(source);
   3896 
   3897 			if (getkind(source) != RPARDELIM) {
   3898 				lhs->rhs = exprlist(source, false, NULL);
   3899 				source->lastis = savedis;
   3900 			}
   3901 
   3902 			expect(source, RPARDELIM, "expected ')'");
   3903 			continue;
   3904 
   3905 		} else if (getkind(source) == LSQRDELIM) {
   3906 			gettok(source);
   3907 
   3908 			lhs->rhs = exprlist(source, false, NULL);
   3909 			source->lastis = savedis;
   3910 
   3911 			expect(source, RSQRDELIM, "expected ']'");
   3912 			continue;
   3913 		}
   3914 
   3915 		gettok(source);
   3916 	}
   3917 
   3918 	/* 'not'-suffix for the binary 'is'-operator (i.e. 'is not') */
   3919 	while (getkind(source) == KIS) {
   3920 		lhs = tokennode(source, lhs);
   3921 		gettok(source);
   3922 
   3923 		lhs->kind = 'O';
   3924 		if (getkind(source) == KNOT)
   3925 			gettok(source), lhs->kind = ONEQ;
   3926 		else
   3927 			lhs->kind = OEQU;
   3928 
   3929 		source->lastis = lhs;
   3930 		lhs->rhs = readexpr(source, PRELAT);
   3931 	}
   3932 
   3933 	/* skip funtion-call without parentheses when next token is an
   3934 	 * auxiliary keyword */
   3935 	if (getkind(source) == IDENT) {
   3936 		if (source->tok.u.key == auxthen
   3937 		||  source->tok.u.key == auxin
   3938 		||  source->tok.u.key == auxto
   3939 		||  source->tok.u.key == auxstep) {
   3940 			return lhs;
   3941 		}
   3942 	}
   3943 
   3944 	/* function call without parentheses */
   3945 	if (lhs->kind == ADECLREF
   3946 	&&  lhs->u.declref->kind == DFUNCTION
   3947 	&&  isatomnode(getkind(source))) {
   3948 		lhs = tokennode(source, lhs);
   3949 		lhs->kind = OCALL;
   3950 
   3951 		lhs->rhs = exprlist(source, false, NULL);
   3952 		source->lastis = savedis; /* @note is this correct? */
   3953 
   3954 	/* function call without parentheses for type.function */
   3955 	} else if (lhs->kind == ODISP
   3956 		&& lhs->lhs->type && lhs->lhs->type->module) {
   3957 		Decl *field;
   3958 		
   3959 		assert(lhs->lhs->type->module->contentenv);
   3960 		field = finddeclinenv(lhs->rhs->u.key,
   3961 			lhs->lhs->type->module->contentenv);
   3962 		if (field && field->kind == DFUNCTION
   3963 		&&  isatomnode(getkind(source))) {
   3964 			lhs = tokennode(source, lhs);
   3965 			lhs->kind = OCALL;
   3966 
   3967 			lhs->rhs = exprlist(source, false, NULL);
   3968 			source->lastis = savedis; /* @note is this correct? */
   3969 		}
   3970 	}
   3971 
   3972 	return lhs;
   3973 }
   3974 
   3975 // }}}
   3976 
   3977 // @sub-section read expression {{{
   3978 
   3979 static Node *
   3980 readexpr(Source *source, int minprec)
   3981 {
   3982 	Node *lhs = readatom(source, 0), *last = NULL;
   3983 
   3984 	/* only binary expr */
   3985 	while (getprec(getkind(source)) >= minprec) {
   3986 		lhs = tokennode(source, lhs);
   3987 		gettok(source);
   3988 		skipnewline(source);
   3989 
   3990 		lhs->rhs = readexpr(
   3991 			source,
   3992 			getprec(lhs->kind) + !israssoc(lhs->kind)
   3993 		);
   3994 
   3995 		switch (getprec(lhs->kind)) {
   3996 		case PRELAT:
   3997 			if (last) {
   3998 				lhs = tokennode(source, lhs);
   3999 
   4000 				lhs->rhs = lhs->lhs;
   4001 				lhs->kind = OLAND;
   4002 
   4003 				lhs->lhs = lhs->rhs->lhs;
   4004 				lhs->rhs->lhs = last->rhs; /* copy */
   4005 				last = lhs->rhs;
   4006 			} else {
   4007 				last = lhs;
   4008 			}
   4009 
   4010 			break;
   4011 
   4012 		default:
   4013 			last = NULL;
   4014 			break;
   4015 		}
   4016 	}
   4017 
   4018 	return lhs;
   4019 }
   4020 
   4021 #if 0
   4022 static Node *
   4023 todeclaration(Node *curr, Node **ty)
   4024 {
   4025 	if (*ty) {
   4026 		if (curr->kind == IDENT) {
   4027 			Node *decl = makenode(curr, *ty);
   4028 			curr->kind = ADECL;
   4029 			decl->rhs = curr;
   4030 			curr = decl;
   4031 		} else if (curr->kind == OASS &&
   4032 		           curr->lhs && curr->lhs->kind == IDENT)
   4033 		{
   4034 			curr->kind = ADECL;
   4035 			curr->u.payload = curr->rhs;
   4036 			curr->rhs = curr->lhs;
   4037 			curr->lhs = *ty;
   4038 		}
   4039 	}
   4040 
   4041 	if (curr->kind == ADECL)
   4042 		*ty = curr->lhs;
   4043 
   4044 	return curr;
   4045 }
   4046 #endif
   4047 
   4048 /* @todo this is stupid! There should be a simpler way to parse the
   4049  *              comma-expressions (comma-operator, param-list, declaration-list,
   4050  *              type-tuples and expression-tuples) */
   4051 static Node *
   4052 exprlist(Source *source, bool isparam, Type *paramtype)
   4053 {
   4054 	Node *lhs;
   4055 	bool isdeclaration, typetuple;
   4056 
   4057 	/* tail = todeclaration(tail, &paramtype); */
   4058 
   4059 	if (paramtype && getkind(source) == IDENT) {
   4060 		lhs = declaration(source, paramtype, true);
   4061 	} else {
   4062 		lhs = readexpr(source, PASSIGN);
   4063 	}
   4064 
   4065 	isdeclaration = lhs->kind == ADECL;
   4066 
   4067 	if (isdeclaration)
   4068 		paramtype = lhs->type;
   4069 	else if (isparam)
   4070 		error(getloc(source), "expected declaration");
   4071 
   4072 	typetuple = lhs->kind == TYPE;
   4073 
   4074 	while (getkind(source) == COMMADELIM) {
   4075 		Node *rhs = NULL;
   4076 
   4077 		if (lhs->kind == ACOMMA &&
   4078 		    lhs->lhs->kind == TYPE &&
   4079 		    lhs->rhs->kind == TYPE)
   4080 		{
   4081 			lhs->type = maketype(&source->arenas, &lhs->loc,
   4082 				primitive(TTUPLE), lhs->lhs->type);
   4083 			lhs->type->u.rtarget = lhs->rhs->type;
   4084 
   4085 			lhs->lhs->type = NULL;
   4086 			lhs->rhs->type = NULL;
   4087 			deletenode(lhs->lhs);
   4088 			deletenode(lhs->rhs);
   4089 
   4090 			lhs->lhs = NULL;
   4091 			lhs->rhs = NULL;
   4092 			lhs->kind = TYPE;
   4093 		}
   4094 
   4095 		lhs = tokennode(source, lhs);
   4096 		lhs->kind = ACOMMA;
   4097 		gettok(source);
   4098 
   4099 		if (getkind(source) == IDENT && isdeclaration) {
   4100 			rhs = declaration(source, paramtype, true);
   4101 			typetuple = false;
   4102 		} else {
   4103 			rhs = readexpr(source, PASSIGN);
   4104 			typetuple &= rhs->kind == TYPE;
   4105 			/* rhs = todeclaration(curr, &paramtype); */
   4106 		}
   4107 
   4108 		if ((paramtype || isparam) && rhs->kind != ADECL)
   4109 			error(getloc(source), "expected declaration");
   4110 
   4111 		if (rhs->kind == ADECL) {
   4112 			paramtype = rhs->type;
   4113 			isdeclaration = true;
   4114 		}
   4115 
   4116 		lhs->rhs = rhs;
   4117 	}
   4118 
   4119 	source->lastis = NULL;
   4120 	return lhs;
   4121 }
   4122 
   4123 // }}}
   4124 
   4125 
   4126 
   4127 // }}}
   4128 
   4129 // @section type-checking & folding {{{
   4130 
   4131 static bool
   4132 isinttype(Type *ty)
   4133 {
   4134 	switch (ty->kind) {
   4135 	case TINFER: case TUINFER:
   4136 	case TS8:    case TU8:
   4137 	case TS16:   case TU16:
   4138 	case TS32:   case TU32:
   4139 	case TS64:   case TU64:
   4140 	case TERRTYPE: /* avoiding error-reporting on error-type */
   4141 		return true;
   4142 
   4143 	/* FIXME(m21c): This *just* tests wether a tuple only contains types of
   4144 	 *               certain kinds. In order to check wether two tuple-types
   4145 	 *               are compatible (for casting), another function has to
   4146 	 *               be implemented. */
   4147 	case TTUPLE:
   4148 		return isinttype(ty->target)
   4149 		    && isinttype(ty->u.rtarget);
   4150 
   4151 	default:
   4152 		return false;
   4153 	}
   4154 }
   4155 
   4156 static bool
   4157 isintorbooltype(Type *ty)
   4158 {
   4159 	switch (ty->kind) {
   4160 	case TBOOL:
   4161 	case TINFER: case TUINFER:
   4162 	case TS8:    case TU8:
   4163 	case TS16:   case TU16:
   4164 	case TS32:   case TU32:
   4165 	case TS64:   case TU64:
   4166 	case TERRTYPE: /* avoiding error-reporting on error-type */
   4167 		return true;
   4168 
   4169 	/* FIXME(m21c): This *just* tests wether a tuple only contains types of
   4170 	 *               certain kinds. In order to check wether two tuple-types
   4171 	 *               are compatible (for casting), another function has to
   4172 	 *               be implemented. */
   4173 	case TTUPLE:
   4174 		return isintorbooltype(ty->target)
   4175 		    && isintorbooltype(ty->u.rtarget);
   4176 
   4177 	default:
   4178 		return false;
   4179 	}
   4180 }
   4181 
   4182 static bool
   4183 isfloattype(Type *ty)
   4184 {
   4185 	switch (ty->kind) {
   4186 	case TF32: case TF64:
   4187 	case TERRTYPE: /* avoiding error-reporting on error-type */
   4188 		return true;
   4189 
   4190 	/* FIXME(m21c): This *just* tests wether a tuple only contains types of
   4191 	 *               certain kinds. In order to check wether two tuple-types
   4192 	 *               are compatible (for casting), another function has to
   4193 	 *               be implemented. */
   4194 	case TTUPLE:
   4195 		return isfloattype(ty->target)
   4196 		    && isfloattype(ty->u.rtarget);
   4197 
   4198 	default:
   4199 		return false;
   4200 	}
   4201 }
   4202 
   4203 static bool
   4204 isarithtype(Type *ty)
   4205 {
   4206 	switch (ty->kind) {
   4207 	case TBOOL:
   4208 	case TINFER: case TUINFER:
   4209 	case TS8:    case TU8:
   4210 	case TS16:   case TU16:
   4211 	case TS32:   case TU32:
   4212 	case TS64:   case TU64:
   4213 	case TF32:   case TF64:
   4214 	case TERRTYPE: /* avoiding error-reporting on error-type */
   4215 		return true;
   4216 
   4217 	/* FIXME(m21c): This *just* tests wether a tuple only contains types of
   4218 	 *               certain kinds. In order to check wether two tuple-types
   4219 	 *               are compatible (for casting), another function has to
   4220 	 *               be implemented. */
   4221 	case TTUPLE:
   4222 		return isarithtype(ty->target)
   4223 		    && isarithtype(ty->u.rtarget);
   4224 
   4225 	default:
   4226 		return false;
   4227 	}
   4228 }
   4229 
   4230 /* @note essentially arithmetic + reference type */
   4231 static bool
   4232 islogicaltype(Type *ty)
   4233 {
   4234 	switch (ty->kind) {
   4235 	case TBOOL:
   4236 	case TINFER: case TUINFER:
   4237 	case TS8:    case TU8:
   4238 	case TS16:   case TU16:
   4239 	case TS32:   case TU32:
   4240 	case TS64:   case TU64:
   4241 	case TF32:   case TF64:
   4242 	case TPTR:
   4243 	/* @todo add ranges ? */
   4244 	case TERRTYPE: /* avoiding error-reporting on error-type */
   4245 		return true;
   4246 
   4247 	/* FIXME(m21c): This *just* tests wether a tuple only contains types of
   4248 	 *               certain kinds. In order to check wether two tuple-types
   4249 	 *               are compatible (for casting), another function has to
   4250 	 *               be implemented. */
   4251 	case TTUPLE:
   4252 		return islogicaltype(ty->target)
   4253 		    && islogicaltype(ty->u.rtarget);
   4254 
   4255 	default:
   4256 		return false;
   4257 	}
   4258 }
   4259 
   4260 static bool
   4261 isunsignedtype(Type *ty)
   4262 {
   4263 	switch (ty->kind) {
   4264 	case TBOOL:
   4265 	case TUINFER:
   4266 	case TU8:   case TU16:
   4267 	case TU32:  case TU64:
   4268 	case TERRTYPE: /* avoiding error-reporting on error-type */
   4269 		return true;
   4270 
   4271 	/* FIXME(m21c): This *just* tests wether a tuple only contains types of
   4272 	 *               certain kinds. In order to check wether two tuple-types
   4273 	 *               are compatible (for casting), another function has to
   4274 	 *               be implemented. */
   4275 	case TTUPLE:
   4276 		return isunsignedtype(ty->target)
   4277 		    && isunsignedtype(ty->u.rtarget);
   4278 
   4279 	default:
   4280 		return false;
   4281 	}
   4282 }
   4283 
   4284 static bool
   4285 islvalue(Node *node)
   4286 {
   4287 	assert(node);
   4288 
   4289 	switch (node->kind) {
   4290 	case ADECLREF:
   4291 	case ADEREF:
   4292 	case ADECL:
   4293 	case ODISP: /* only for member fields. @todo evaluate for properties. */
   4294 	case TERRTYPE: /* avoiding error-reporting on error-type */
   4295 		return true;
   4296 
   4297 	/* @note for &array[i] */
   4298 	case OARRAY:
   4299 		/* @todo evaluate target */
   4300 		return true;
   4301 
   4302 	case ACOMMA:
   4303 		return islvalue(node->lhs) && islvalue(node->rhs);
   4304 
   4305 	default:
   4306 		return false;
   4307 	}
   4308 }
   4309 
   4310 /* @todo also mask int/float values in the tokenizer */
   4311 static uintmax_t
   4312 maskint(int size, uintmax_t value)
   4313 {
   4314 	if (size == 1) return value & 0xfful;
   4315 	if (size == 2) return value & 0xfffful;
   4316 	if (size == 4) return value & 0xfffffffful;
   4317 
   4318 	return value;
   4319 }
   4320 
   4321 static double
   4322 maskfloat(int size, double value)
   4323 {
   4324 	if (size == 4) return (double) (float) value;
   4325 
   4326 	return value;
   4327 }
   4328 
   4329 static uintmax_t
   4330 convint(int srcsize, bool srcsigned, uintmax_t value)
   4331 {
   4332 	if (!srcsigned) return value;
   4333 	if (srcsize == 1) return (uintmax_t) (int8_t ) value;
   4334 	if (srcsize == 2) return (uintmax_t) (int16_t) value;
   4335 	if (srcsize == 4) return (uintmax_t) (int32_t) value;
   4336 
   4337 	return value;
   4338 }
   4339 
   4340 static Node *
   4341 conv(Env *env, Node *node);
   4342 
   4343 static Node *
   4344 wrap(Env *env, Type *type, Node *node)
   4345 {
   4346 	Type *nodetype = node->type;
   4347 
   4348 	assert(type);
   4349 
   4350 	// @todo add error-reporting | refactor
   4351 	if (!nodetype) {
   4352 		printf("node has no type\n");
   4353 	}
   4354 
   4355 	assert(nodetype);
   4356 
   4357 	/* @todo do proper type-check */
   4358 	if (type->kind == nodetype->kind)
   4359 		return node;
   4360 
   4361 	if (node->kind == NUMBER) {
   4362 		/* @todo layout correct type-conversions ? */
   4363 		if (isfloattype(nodetype)) {
   4364 			if (isfloattype(type)) {
   4365 				node->u.d = maskfloat(
   4366 					type->size,
   4367 					node->u.d
   4368 				);
   4369 
   4370 			} else if (isintorbooltype(type)) {
   4371 				node->u.u = maskint(
   4372 					type->size,
   4373 					(intmax_t) node->u.d
   4374 				);
   4375 			}
   4376 		} else if (isintorbooltype(nodetype)) {
   4377 			if (isfloattype(type)) {
   4378 				node->u.d = maskfloat(
   4379 					type->size, (double)
   4380 					(intmax_t) convint(node->type->size,
   4381 						!isunsignedtype(node->type),
   4382 						node->u.u
   4383 					)
   4384 				);
   4385 
   4386 			} else if (isintorbooltype(type)) {
   4387 				node->u.u = maskint(
   4388 					type->size,
   4389 					convint(
   4390 						nodetype->size,
   4391 						!isunsignedtype(nodetype),
   4392 						node->u.u
   4393 					)
   4394 				);
   4395 			}
   4396 		}
   4397 
   4398 		node->type = type;
   4399 		return node;
   4400 	}
   4401 
   4402 	/* @note no implicit (de-)referencing if the wrap-type is bool */
   4403 	if (type->kind == TBOOL)
   4404 		goto doconversion;
   4405 
   4406 	/* @todo skip implicit (de-)referencing on arithmetic
   4407 	 *              conversion, also skip if called from conv() */
   4408 
   4409 	/* implicit referencing: */
   4410 	if (type->kind == TPTR && type->target->kind == nodetype->kind) {
   4411 		node = makenode(env->arenas, node, node);
   4412 		node->kind = OADDR;
   4413 		node->type = type->target;
   4414 
   4415 		/* @todo check for lvalue & maybe do further
   4416 		 *              type-checks*/
   4417 		return node;
   4418 	}
   4419 
   4420 	/* implicit de-referencing: */
   4421 	if (nodetype->kind == TPTR && nodetype->target->kind == type->kind) {
   4422 		node = makenode(env->arenas, node, node);
   4423 		node->kind = ODEREF;
   4424 		node->type = type;
   4425 
   4426 		/* @todo maybe do further type-checks*/
   4427 		return node;
   4428 	}
   4429 
   4430 doconversion:
   4431 	node = makenode(env->arenas, node, node);
   4432 	node->kind = ACONV;
   4433 	node->type = type;
   4434 
   4435 	return node;
   4436 }
   4437 
   4438 static Node *
   4439 conv(Env *env, Node *node)
   4440 {
   4441 	Type *ty = node->type;
   4442 
   4443 	assert(ty);
   4444 
   4445 	if (ty->kind == TINFER)
   4446 		return wrap(env, primitive(TINT), node);
   4447 
   4448 	if (ty->kind == TUINFER)
   4449 		return wrap(env, primitive(TUINT), node);
   4450 
   4451 	return node;
   4452 }
   4453 
   4454 
   4455 static bool
   4456 arithtuplereorder(Env *env, Node *expr, int numops)
   4457 {
   4458 	Node *tmp;
   4459 
   4460 	(void) env;
   4461 
   4462 	if (numops == 2) {
   4463 		if (expr->lhs->kind != ACOMMA)
   4464 			return false;
   4465 
   4466 		if (expr->rhs->kind != ACOMMA)
   4467 			return false;
   4468 
   4469 		/* (a, b) OP (x, y)  ==>  (a OP x, b OP y) */
   4470 		expr->lhs->kind = expr->kind;
   4471 		expr->rhs->kind = expr->kind;
   4472 		expr->kind = ACOMMA;
   4473 
   4474 		tmp = expr->lhs->rhs;
   4475 		expr->lhs->rhs = expr->rhs->lhs;
   4476 		expr->rhs->lhs = tmp;
   4477 
   4478 		return true;
   4479 	}
   4480 
   4481 	if (numops == 1) {
   4482 		if (expr->lhs->kind != ACOMMA)
   4483 			return false;
   4484 
   4485 		/* OP (a, b)  ==>  (OP a, OP b) */
   4486 		expr->lhs->kind = expr->kind;
   4487 
   4488 		tmp = expr->rhs;
   4489 		expr->rhs = makenode(env->arenas, expr, expr->lhs->rhs);
   4490 		expr->lhs->rhs = tmp; /* @note some unary nodes may have a rhs? */
   4491 		expr->rhs->rhs = tmp; /* @todo make a copy */
   4492 		expr->kind = ACOMMA;
   4493 
   4494 		return true;
   4495 	}
   4496 
   4497 	return false;
   4498 }
   4499 
   4500 static Type *
   4501 typecheckdecl(Env *env, Decl *decl)
   4502 {
   4503 	if (decl->kind == DPARAM || decl->kind == DVAR) {
   4504 		if (!decl->u.content)
   4505 			return decl->type;
   4506 
   4507 		decl->u.content = typecheck(env, decl->u.content);
   4508 
   4509 		if (decl->type->kind == TINFER) {
   4510 			decl->u.content = conv(env, decl->u.content);
   4511 			decl->type = decl->u.content->type;
   4512 		} else {
   4513 			decl->u.content = wrap(env, decl->type, decl->u.content);
   4514 		}
   4515 	} else if (decl->kind == DFUNCTION) {
   4516 		if (!decl->u.content)
   4517 			return decl->type;
   4518 
   4519 		assert(decl->contentenv);
   4520 		if (decl->contentenv->pending)
   4521 			return decl->type;
   4522 
   4523 		decl->u.content = typecheck(env, decl->u.content);
   4524 	}
   4525 
   4526 	return decl->type;
   4527 }
   4528 
   4529 static Node *
   4530 substitutedispatch(Env *env, Node *expr)
   4531 {
   4532 #if 0
   4533 	/* This is wrong (tuple != comma-operator)*/
   4534 	assert(expr->u.declref);
   4535 	assert(expr->type == expr->u.declref->type);
   4536 
   4537 	expr->kind = ACOMMA;
   4538 	expr->type = maketype(&expr->loc, primitive(TTUPLE), expr->lhs->type);
   4539 
   4540 	expr->rhs->kind = ADECLREF;
   4541 	expr->rhs->u.declref = expr->u.declref;
   4542 	expr->rhs->type = expr->type;
   4543 
   4544 	expr->type->u.rtarget = expr->lhs->type;
   4545 	return expr;
   4546 #else
   4547 	Node *result = makenode(env->arenas, expr, NULL);
   4548 	result->kind = ADECLREF;
   4549 	result->u.declref = expr->u.declref;
   4550 	result->type = expr->type;
   4551 
   4552 	/* @fixme delete doesnt work (self is used multiple times) */
   4553 	/* deletenode(expr); */
   4554 	return result;
   4555 #endif
   4556 }
   4557 
   4558 static Node *
   4559 substitutedispatchcall(Env *env, Node *expr)
   4560 {
   4561 	Decl *field = expr->lhs->u.declref;
   4562 	assert(field);
   4563 
   4564 	if (field->flags & MRECORDMEMBER) {
   4565 		expr->lhs->kind = ODISP;
   4566 		return expr;
   4567 	}
   4568 
   4569 	expr->lhs = substitutedispatch(env, expr->lhs);
   4570 	return expr;
   4571 }
   4572 
   4573 static Node *
   4574 selfdispatchcall(Env *env, Node *expr)
   4575 {
   4576 	Node *self, *probe, *insert;
   4577 
   4578 	assert(expr && expr->kind == OCALL);
   4579 
   4580 	if (expr->lhs->kind != ASELFDISP)
   4581 		return expr;
   4582 
   4583 	self = expr->lhs->lhs;
   4584 	assert(self);
   4585 	assert(self->type);
   4586 
   4587 	if (self->type->kind == TSTRUCT || self->type->kind == TUNION) {
   4588 		self = makenode(env->arenas, self, self);
   4589 		self->kind = OADDR;
   4590 		self->type = maketype(
   4591 			env->arenas, &self->loc,
   4592 			primitive(TINT), self->type);
   4593 	} else if (self->type->kind != TPTR) {
   4594 		error(&self->loc, "expected struct or union or pointer type");
   4595 	} else if (self->type->target->kind != TSTRUCT &&
   4596 	           self->type->target->kind != TUNION) {
   4597 		error(&self->loc, "expected pointer to struct or union type");
   4598 	}
   4599 
   4600 	if (!expr->rhs) {
   4601 		expr->rhs = self;
   4602 		return substitutedispatchcall(env, expr);
   4603 	}
   4604 
   4605 	if (expr->rhs->kind != ACOMMA) {
   4606 		insert = makenode(env->arenas, expr->rhs, self);
   4607 		insert->kind = ACOMMA;
   4608 		insert->rhs = expr->rhs;
   4609 		expr->rhs = insert;
   4610 
   4611 		return substitutedispatchcall(env, expr);
   4612 	}
   4613 
   4614 	probe = expr->rhs;
   4615 	while (probe->lhs && probe->lhs->kind == ACOMMA)
   4616 		probe = probe->lhs;
   4617 
   4618 	insert = makenode(env->arenas, probe, self);
   4619 	insert->rhs = probe->lhs;
   4620 	probe->lhs = insert;
   4621 
   4622 	return substitutedispatchcall(env, expr);
   4623 }
   4624 
   4625 static Node *
   4626 resolvepending(Env *env, Node *expr)
   4627 {
   4628 	Decl *decl;
   4629 
   4630 	assert(expr->kind == IDENT);
   4631 
   4632 	decl = finddeclaration(NULL, env, expr->u.key);
   4633 
   4634 	if (!decl) {
   4635 		error(&expr->loc, "'%s' undeclared",
   4636 			getstring(idents, expr->u.key));
   4637 
   4638 		return expr;
   4639 	}
   4640 
   4641 	if (decl->kind != DVAR && decl->kind != DFUNCTION) {
   4642 		error(&expr->loc, "'%s' is not a variable nor a function",
   4643 			getstring(idents, expr->u.key));
   4644 
   4645 		return expr;
   4646 	}
   4647 
   4648 	expr->kind = ADECLREF;
   4649 	expr->u.declref = decl;
   4650 	expr->type = decl->type;
   4651 
   4652 	return typecheck(env, expr);
   4653 }
   4654 
   4655 static Node *
   4656 dispatch(Env *env, Node *expr, Node *parent)
   4657 {
   4658 	Type *type;
   4659 	Decl *field;
   4660 
   4661 	/* @note might change in future */
   4662 	assert(expr->lhs);
   4663 	type = expr->lhs->type;
   4664 	assert(type);
   4665 
   4666 	/* @todo maybe do implicit dereference */
   4667 	if (type->kind == TPTR) {
   4668 		Node *lhs = makenode(env->arenas, expr->lhs, expr->lhs);
   4669 		lhs->kind = ADEREF;
   4670 		lhs->type = type->target;
   4671 
   4672 		type = type->target;
   4673 		expr->lhs = lhs;
   4674 	}
   4675 
   4676 	if (type->kind != TSTRUCT && type->kind != TUNION) {
   4677 		error(&expr->lhs->loc, "expected struct or union type");
   4678 		return expr;
   4679 	}
   4680 
   4681 	/* @note might change in future */
   4682 	assert(expr->rhs);
   4683 	assert(expr->rhs->kind == IDENT);
   4684 
   4685 	/* @note improvised for now */
   4686 	assert(type->module->contentenv);
   4687 	field = finddeclinenv(expr->rhs->u.key, type->module->contentenv);
   4688 
   4689 	if (!field) {
   4690 		const char *typekind = type->kind == TSTRUCT ? "struct" : "union";
   4691 		const char *modulename = getstring(idents, type->module->key);
   4692 		const char *fieldname = getstring(idents, expr->rhs->u.key);
   4693 		error(&expr->rhs->loc, "%s '%s' has no field '%s'",
   4694 			typekind, modulename, fieldname);
   4695 		expr->type = primitive(TERRTYPE);
   4696 		return expr;
   4697 	}
   4698 
   4699 	expr->type = field->type;
   4700 	expr->u.declref = field;
   4701 
   4702 	return expr;
   4703 }
   4704 
   4705 static void
   4706 forloop(Env *env, Node *expr, Node *header)
   4707 {
   4708 	if (header->kind == AFORSTEP) {
   4709 		Node *init = header->lhs;
   4710 		if (init->kind == ADECL) {
   4711 			Decl *it = init->u.declref;
   4712 			if (!it->u.content) {
   4713 				if (!isarithtype(it->type)) {
   4714 					error(&it->loc,
   4715 						"for loop variable must be initialized");
   4716 					return;
   4717 				}
   4718 				it->u.content = makenode(
   4719 					env->arenas, header, NULL);
   4720 				it->u.content->kind = NUMBER;
   4721 				it->u.content->type = it->type;
   4722 				it->u.content->u.u = 0;
   4723 			}
   4724 
   4725 			header->lhs = conv(env, typecheck(env, header->lhs));
   4726 		}
   4727 
   4728 		/* @todo do proper typechecking */
   4729 		header->rhs = wrap(
   4730 			env, header->lhs->type, typecheck(env, header->rhs));
   4731 		header->u.payload = wrap(
   4732 			env, header->lhs->type,
   4733 			typecheck(env, header->u.payload));
   4734 		return;
   4735 	}
   4736 
   4737 	if (header->kind == AFOREACH) {
   4738 
   4739 		return;
   4740 	}
   4741 
   4742 	header = expr->u.payload = conv(env, typecheck(env, header));
   4743 
   4744 	if (isarithtype(header->type)) {
   4745 		Decl *it;
   4746 		Node *forstep;
   4747 		
   4748 
   4749 		it = makedecl2(&header->loc, env,
   4750 			getstringkey(&idents, "it", 2), DVAR);
   4751 		it->type = header->type;
   4752 		it->u.content = makenode(env->arenas, header, NULL);
   4753 		it->u.content->kind = NUMBER;
   4754 		it->u.content->type = header->type;
   4755 		it->u.content->u.u = 0;
   4756 
   4757 		forstep = makenode(env->arenas, header, NULL);
   4758 		forstep->kind = AFORSTEP;
   4759 		forstep->type = header->type;
   4760 
   4761 		forstep->lhs = makenode(env->arenas, header, NULL);
   4762 		forstep->lhs->kind = ADECL;
   4763 		forstep->lhs->u.declref = it;
   4764 
   4765 		forstep->rhs = header;
   4766 
   4767 		forstep->u.payload = makenode(env->arenas, header, NULL);
   4768 		forstep->u.payload->kind = NUMBER;
   4769 		forstep->u.payload->type = header->type;
   4770 		/* @todo handle negative step when possible
   4771 		 *       (i.e. when header is signed and constant) */
   4772 		if (isfloattype(header->type))
   4773 			forstep->u.payload->u.d = 1.0;
   4774 		else
   4775 			forstep->u.payload->u.u = 1;
   4776 	
   4777 		expr->u.payload = forstep;
   4778 		return;
   4779 	}
   4780 
   4781 	/* @todo handle other cases (e.g. arrays/strings/lists/iterators) */
   4782 	error(&expr->loc, "invalid loop header");
   4783 }
   4784 
   4785 Node *parentnodes[1024];
   4786 int parenttop = 0;
   4787 
   4788 static Node *
   4789 typecheck(Env *env, Node *expr)
   4790 {
   4791 	#define return return --parenttop, 
   4792 
   4793 	Node *lhs = expr->lhs, *rhs = expr->rhs;
   4794 
   4795 	parentnodes[parenttop++] = expr;
   4796 
   4797 	#define errortype(condition) do { \
   4798 		if (condition) { \
   4799 			expr->type = primitive(TERRTYPE); \
   4800 			return expr; \
   4801 		} \
   4802 	} while (0)
   4803 
   4804 	#define reporton(condition, loc, errormsg) do { \
   4805 		if (condition) { \
   4806 			error((loc), (errormsg)); \
   4807 			expr->type = primitive(TERRTYPE); \
   4808 			return expr; \
   4809 		} \
   4810 	} while (0)
   4811 
   4812 	switch (getnumops(expr->kind)) {
   4813 	case 2:
   4814 		assert(rhs);
   4815 		errortype(rhs->type->kind == TERRTYPE);
   4816 		rhs = typecheck(env, rhs);
   4817 		/* FALLTHROUGH */
   4818 	case 1:
   4819 		assert(lhs);
   4820 		errortype(lhs->type->kind == TERRTYPE);
   4821 		lhs = typecheck(env, lhs);
   4822 
   4823 		if (arithtuplereorder(env, expr, getnumops(expr->kind)))
   4824 			goto joincomma;
   4825 	}
   4826 
   4827 	if (expr->type && expr->type->kind == TERRTYPE)
   4828 		return expr;
   4829 
   4830 	switch (expr->kind) {
   4831 	case ODISP:
   4832 	case ASELFDISP:
   4833 		lhs = typecheck(env, lhs);
   4834 		expr->lhs = conv(env, lhs);
   4835 
   4836 		if (parenttop > 1)
   4837 			return dispatch(env, expr, parentnodes[parenttop - 2]);
   4838 
   4839 		return dispatch(env, expr, NULL);
   4840 
   4841 	case OCALL:
   4842 		reporton(lhs->type->kind == TPTR && lhs->type->target->kind != TFUNCTION,
   4843 			&expr->loc, "operand is not a pointer to function");
   4844 		
   4845 		reporton(lhs->type->kind != TPTR && lhs->type->kind != TFUNCTION,
   4846 			&expr->loc, "operand is not a function");
   4847 
   4848 		if (lhs->type->kind == TFUNCTION)
   4849 			expr->type = lhs->type->u.rtarget;
   4850 		else
   4851 			expr->type = lhs->type->target->u.rtarget;
   4852 		
   4853 		expr = selfdispatchcall(env, expr);
   4854 		expr->rhs = typecheck(env, expr->rhs);
   4855 		return expr;
   4856 	
   4857 	case OARRAY:
   4858 		expr->lhs = conv(env, lhs);
   4859 		reporton(lhs->type->kind != TARRAY && lhs->type->kind != TPTR,
   4860 			&expr->loc, "operand is not an array or pointer");
   4861 
   4862 		expr->rhs = typecheck(env, rhs);
   4863 
   4864 		/* @todo handle negative indices when possible (use unsigned) */
   4865 		reporton(!isinttype(rhs->type),
   4866 			&rhs->loc, "array index is not an integer");
   4867 
   4868 		expr->rhs = wrap(env, primitive(TUSIZE), expr->rhs);
   4869 		
   4870 		expr->type = lhs->type->target;
   4871 		return expr;
   4872 
   4873 	case OINC: case ODEC: case OSUFINC: case OSUFDEC:
   4874 		reporton(!islvalue(lhs),
   4875 			&expr->loc, "operand is not an lvalue");
   4876 
   4877 		expr->lhs = conv(env, lhs);
   4878 		expr->type = lhs->type;
   4879 		return expr;
   4880 
   4881 	case ODEREF:
   4882 		expr->type = lhs->type;
   4883 
   4884 		reporton(expr->type->kind != TPTR,
   4885 			&expr->loc, "operand is not a pointer");
   4886 
   4887 		expr->type = expr->type->target;
   4888 		return expr;
   4889 
   4890 	case OADDR:
   4891 		reporton(!islvalue(lhs),
   4892 			&expr->loc, "operand is not an lvalue");
   4893 
   4894 		expr->type = maketype(
   4895 			env->arenas, &expr->loc,
   4896 			primitive(TPTR), lhs->type);
   4897 		return expr;
   4898 
   4899 	case OPLUS: case OMINUS:
   4900 		/*
   4901 		reporton(!isarithtype(lhs->type),
   4902 			&lhs->loc, "expression is not of arithmetic type");
   4903 		*/
   4904 
   4905 		expr->lhs = conv(env, lhs);
   4906 		expr->type = lhs->type;
   4907 		return expr;
   4908 
   4909 	case OBNOT:
   4910 		reporton(!isintorbooltype(lhs->type),
   4911 			&lhs->loc, "expression is not of integer type");
   4912 
   4913 		expr->lhs = conv(env, lhs);
   4914 		expr->type = lhs->type;
   4915 		return expr;
   4916 
   4917 	case OLNOT:
   4918 		reporton(!islogicaltype(lhs->type),
   4919 			&lhs->loc, "expression is not of logical type");
   4920 
   4921 		expr->type = primitive(TBOOL);
   4922 		expr->lhs = conv(env, lhs); /* cannot be wrap(expr->type, lhs) */
   4923 		return expr;
   4924 
   4925 	case OCAST:
   4926 		/*
   4927 		assert(rhs);
   4928 		assert(lhs->kind == TYPE);
   4929 		*/
   4930 
   4931 		if (arithtuplereorder(env, expr, 1))
   4932 			goto joincomma;
   4933 
   4934 		/* expr->type = expr->lhs->type; */
   4935 		return expr;
   4936 
   4937 	case OMUL: case ODIV: case OMOD:
   4938 	case OADD: case OSUB:
   4939 		reporton(!isarithtype(lhs->type) || !isarithtype(rhs->type),
   4940 			&expr->loc, "expression is not of arithmetic type");
   4941 
   4942 		/* usual arithmetic conversion */
   4943 		if (lhs->type->kind < rhs->type->kind)
   4944 			expr->type = rhs->type;
   4945 		else
   4946 			expr->type = lhs->type;
   4947 
   4948 		expr->lhs = wrap(env, expr->type, lhs);
   4949 		expr->rhs = wrap(env, expr->type, rhs);
   4950 		return expr;
   4951 
   4952 	case OBAND: case OBOR: case OXOR:
   4953 		reporton(!isintorbooltype(lhs->type) || !isintorbooltype(rhs->type),
   4954 			&expr->loc, "expression is not of integer type");
   4955 
   4956 		/* usual arithmetic conversion */
   4957 		if (lhs->type->kind < rhs->type->kind)
   4958 			expr->type = rhs->type;
   4959 		else
   4960 			expr->type = lhs->type;
   4961 
   4962 		expr->lhs = wrap(env, expr->type, lhs);
   4963 		expr->rhs = wrap(env, expr->type, rhs);
   4964 		return expr;
   4965 
   4966 	case OLSH: case ORSH: case OARSH:
   4967 		reporton(!isinttype(lhs->type) || !isinttype(rhs->type),
   4968 			&expr->loc, "expression is not of integer type");
   4969 
   4970 		expr->lhs = conv(env, lhs);
   4971 		expr->rhs = wrap(env, primitive(TINT), rhs);
   4972 		expr->type = lhs->type;
   4973 		return expr;
   4974 
   4975 	case OEQU: case ONEQ:
   4976 	case OLET: case OLEQ:
   4977 	case OGRT: case OGEQ:
   4978 		reporton(!isarithtype(lhs->type) || !isarithtype(rhs->type),
   4979 			&expr->loc, "expression is not of arithmetic type");
   4980 
   4981 		expr->lhs = conv(env, lhs);
   4982 		expr->rhs = conv(env, rhs);
   4983 		expr->type = primitive(TBOOL);
   4984 		return expr;
   4985 
   4986 	case OLAND: case OLOR:
   4987 		reporton(!islogicaltype(lhs->type) || !islogicaltype(rhs->type),
   4988 			&expr->loc, "expression is not of logical type");
   4989 
   4990 		expr->type = primitive(TBOOL);
   4991 		expr->lhs = wrap(env, expr->type, lhs);
   4992 		expr->rhs = wrap(env, expr->type, rhs);
   4993 		return expr;
   4994 
   4995 	case OMULA: case ODIVA: case OMODA:
   4996 	case OADDA: case OSUBA:
   4997 		reporton(!isarithtype(lhs->type) || !isarithtype(rhs->type),
   4998 			&expr->loc, "expression is not of arithmetic type");
   4999 		goto joinassign;
   5000 
   5001 	case OLSHA: case ORSHA: case OARSHA:
   5002 	case OANDA:
   5003 	case OORA: case OXORA:
   5004 		reporton(!isinttype(lhs->type) || !isinttype(rhs->type),
   5005 			&expr->loc, "expression is not of integer type");
   5006 		/* FALLTHROUGH */
   5007 
   5008 	case OASS:
   5009 	joinassign:
   5010 		reporton(!islvalue(lhs),
   5011 			&expr->loc, "left-hand-side is not an lvalue");
   5012 
   5013 		expr->lhs = conv(env, lhs);
   5014 		expr->type = lhs->type;
   5015 		expr->rhs = wrap(env, expr->type, rhs);
   5016 		return expr;
   5017 
   5018 	case KIF:
   5019 	case KWHILE:
   5020 	case KUNTIL:
   5021 		assert(expr->u.payload);
   5022 		expr->u.payload = typecheck(env, expr->u.payload);
   5023 		expr->u.payload = wrap(env, primitive(TBOOL), expr->u.payload);
   5024 
   5025 		if (lhs)
   5026 			expr->lhs = typecheck(env, lhs);
   5027 
   5028 		if (rhs)
   5029 			expr->rhs = typecheck(env, rhs);
   5030 
   5031 		/* @todo find a way how we do type-checking for the
   5032 		 *              last expression in a statement-list, which
   5033 		 *              might be needed by the enclosed statement-list
   5034 		 */
   5035 
   5036 		expr->type = primitive(TVOID);
   5037 		return expr;
   5038 
   5039 	case KFOR:
   5040 		assert(expr->u.payload);
   5041 		forloop(env, expr, expr->u.payload);
   5042 
   5043 		if (lhs)
   5044 			expr->lhs = typecheck(env, lhs);
   5045 
   5046 		if (rhs)
   5047 			expr->rhs = typecheck(env, rhs);
   5048 
   5049 		/* @todo infer type of the for-loop like in the case above. */
   5050 
   5051 		expr->type = primitive(TVOID);
   5052 		return expr;
   5053 
   5054 	case AENV:
   5055 	case ASCOPE:
   5056 		assert(lhs);
   5057 		assert(expr->u.env);
   5058 
   5059 		expr->lhs = typecheck(expr->u.env, lhs);
   5060 		return expr;
   5061 
   5062 	case ASTMT:
   5063 		rhs = expr;
   5064 	advancestmt:
   5065 		lhs = typecheck(env, lhs);
   5066 		rhs->lhs = lhs;
   5067 
   5068 		if (rhs->rhs) {
   5069 			assert(rhs->rhs->kind == ASTMT);
   5070 			rhs = rhs->rhs, lhs = rhs->lhs;
   5071 			goto advancestmt;
   5072 		}
   5073 		return expr;
   5074 
   5075 	case ADECL:
   5076 		expr->type = typecheckdecl(env, expr->u.declref);
   5077 		return expr;
   5078 	
   5079 	case ADECLREF:
   5080 		/* @note propagate type changes from ADECL to ADECLREF */
   5081 		expr->type = expr->u.declref->type;
   5082 		return expr;
   5083 
   5084 	case AADDR:
   5085 	case ADEREF:
   5086 		assert(lhs);
   5087 		lhs = typecheck(env, lhs);
   5088 
   5089 		expr->lhs = conv(env, lhs);
   5090 		return expr;
   5091 
   5092 	case ACOMPOUND:
   5093 		assert(lhs);
   5094 		assert(rhs);
   5095 
   5096 		expr->lhs = typecheck(env, lhs);
   5097 		expr->type = lhs->type;
   5098 		expr->rhs = typecheck(env, rhs);
   5099 		return expr;
   5100 
   5101 	case AFIELDINIT:
   5102 		assert(expr->rhs);
   5103 		expr->rhs = typecheck(env, rhs);
   5104 		return expr;
   5105 
   5106 	case IDENT:
   5107 		return resolvepending(env, expr);
   5108 
   5109 	joincomma:
   5110 		lhs = expr->lhs;
   5111 		rhs = expr->rhs;
   5112 		/* FALLTHROUGH */
   5113 	case ACOMMA:
   5114 		assert(lhs);
   5115 		assert(rhs);
   5116 
   5117 		/* @todo make sure that typechecking is done
   5118 		 *              correctly, since comma might be re-
   5119 		 *              ordered:
   5120 		 *                  - check that maketype is NOT called
   5121 		 *                    multiple times and/or discarded on
   5122 		 *                    the same node.
   5123 		 *                  - check wether the resulting type
   5124 		 *                    does account for nesting on rhs */
   5125 		errortype(lhs->type->kind == TERRTYPE);
   5126 		errortype(rhs->type->kind == TERRTYPE);
   5127 
   5128 		lhs = typecheck(env, lhs);
   5129 		rhs = typecheck(env, rhs);
   5130 
   5131 		/* @note converting nodes may be uneccessary */
   5132 		expr->lhs = conv(env, lhs);
   5133 		expr->rhs = conv(env, rhs);
   5134 
   5135 		expr->type = maketype(
   5136 			env->arenas, &expr->loc,
   5137 			primitive(TTUPLE), lhs->type);
   5138 		expr->type->u.rtarget = rhs->type;
   5139 		return expr;
   5140 
   5141 	case KBITCAST:
   5142 		assert(lhs);
   5143 		assert(rhs);
   5144 
   5145 		expr->lhs = lhs = typecheck(env, lhs);
   5146 
   5147 		errortype(lhs->type->kind == TERRTYPE);
   5148 		errortype(rhs->type->kind == TERRTYPE);
   5149 		reporton(rhs->kind != TYPE, &rhs->loc, "expected type");
   5150 
   5151 		expr->type = rhs->type;
   5152 		return expr;
   5153 
   5154 	case KSIZEOF:
   5155 	case KALIGNOF:
   5156 	case KLENGTHOF:
   5157 		assert(lhs);
   5158 
   5159 		expr->lhs = lhs = typecheck(env, lhs);
   5160 		errortype(lhs->type->kind == TERRTYPE);
   5161 
   5162 		expr->type = primitive(TUSIZE);
   5163 		return expr;
   5164 
   5165 	case KRETURN:
   5166 		rhs = expr->rhs;
   5167 
   5168 		if (rhs) {
   5169 			expr->rhs = rhs = typecheck(env, rhs);
   5170 			errortype(rhs->type->kind == TERRTYPE);
   5171 		}
   5172 
   5173 		do {
   5174 			Env *funcenv = getfuncenv(env);
   5175 			Type *functype;
   5176 
   5177 			reporton(
   5178 				!funcenv, &expr->loc,
   5179 				"return statement is not inside a function");
   5180 
   5181 			assert(funcenv->envdecl);
   5182 			assert(funcenv->envdecl->type);
   5183 
   5184 			functype = funcenv->envdecl->type;
   5185 
   5186 			assert(functype->kind == TFUNCTION);
   5187 			assert(functype->u.rtarget);
   5188 
   5189 			expr->type = functype->u.rtarget;
   5190 		} while (0);
   5191 
   5192 		reporton(expr->type->kind == TVOID &&
   5193 		         rhs && rhs->type->kind != TVOID,
   5194 			&expr->loc, "expected no return value");
   5195 
   5196 		reporton(expr->type->kind != TVOID &&
   5197 		         (!rhs || rhs->type->kind == TVOID),
   5198 			&expr->loc, "expected return value");
   5199 
   5200 		if (rhs)
   5201 			expr->lhs = wrap(env, expr->type, rhs);
   5202 
   5203 		return expr;
   5204 
   5205 	default:
   5206 		return expr;
   5207 	}
   5208 
   5209 	#undef errortype
   5210 	#undef reporton
   5211 	#undef return
   5212 }
   5213 
   5214 static Node *
   5215 foldexpr(Env *env, Node *expr);
   5216 
   5217 static Node *
   5218 folddeclaration(Env *env, Node *expr)
   5219 {
   5220 	Decl *decl = expr->u.declref;
   5221 
   5222 	assert(decl);
   5223 
   5224 	if (decl->kind == DFUNCTION) {
   5225 		if (decl->u.content)
   5226 			/* @todo make sure the correct env is used */
   5227 			decl->u.content = foldexpr(env, decl->u.content);
   5228 
   5229 	} else if (decl->kind == DPARAM || decl->kind == DVAR) {
   5230 
   5231 		/* @todo remove condition. it is only for testing structs.
   5232 		 *       content may not be NULL otherwise (needs validation) */
   5233 		if (decl->u.content)
   5234 			decl->u.content = foldexpr(env, decl->u.content);
   5235 	}
   5236 
   5237 	return expr;
   5238 }
   5239 
   5240 static Node *
   5241 folddispatch(Env *env, Node *expr)
   5242 {
   5243 	Node *lhs = expr->lhs, *rhs = expr->rhs;
   5244 	Decl *field = expr->u.declref;
   5245 
   5246 	assert(expr->kind == ODISP && lhs->kind == TYPE);
   5247 	assert(field);
   5248 
   5249 	/* @note field decl is already assigned to
   5250 	 *       expr->u.declref by dispatch() */
   5251 	expr->kind = ADECLREF;
   5252 	expr->rhs = NULL;
   5253 	expr->lhs = NULL;
   5254 	/* deletenode(lhs); */
   5255 	/* deletenode(rhs); */
   5256 	return foldexpr(env, expr);
   5257 }
   5258 
   5259 static Node *
   5260 foldexpr(Env *env, Node *expr)
   5261 {
   5262 	Node *lhs = expr->lhs, *rhs = expr->rhs;
   5263 	Type *ty = expr->type;
   5264 
   5265 
   5266 	#define evalbinary(op) do { \
   5267 			expr->kind = NUMBER; \
   5268 			if (isfloattype(ty)) \
   5269 				expr->u.d = maskfloat(ty->size, \
   5270 					maskfloat(ty->size, lhs->u.d)  op \
   5271 					maskfloat(ty->size, rhs->u.d) \
   5272 				); \
   5273 			else if (isintorbooltype(ty)) \
   5274 				expr->u.u = maskint(ty->size, \
   5275 					maskint(ty->size, lhs->u.u) op \
   5276 					maskint(ty->size, rhs->u.u) \
   5277 				); \
   5278 			deletenode(lhs); \
   5279 			deletenode(rhs); \
   5280 		} while (0)
   5281 
   5282 	#define isvalue(expr, value) (expr->kind == NUMBER && \
   5283 		((expr->u.u == value && isintorbooltype(ty)) || \
   5284 		 (expr->u.d == value && isarithtype(ty))))
   5285 
   5286 	/* @todo maybe modify getnumops() in such a way, that it
   5287 		*              will behave properly for non-operator nodes too */
   5288 	switch (getnumops(expr->kind)) {
   5289 	case 2:
   5290 		rhs = foldexpr(env, rhs);
   5291 		/* FALLTHROUGH */
   5292 	case 1:
   5293 		if (expr->kind == ODISP && lhs->kind == TYPE)
   5294 			return folddispatch(env, expr);
   5295 		lhs = foldexpr(env, lhs);
   5296 	}
   5297 
   5298 	switch ((int) expr->kind) {
   5299 	case OADD: case OSUB:
   5300 		if (lhs->kind == NUMBER && rhs->kind == NUMBER) {
   5301 			if (expr->kind == OADD) evalbinary(+);
   5302 			else evalbinary(-);
   5303 		} else if (isvalue(lhs, 0)) {
   5304 			if (expr->kind == OADD) {
   5305 				*expr = *rhs;
   5306 				deletenode(lhs);
   5307 				deletenode(rhs);
   5308 			} else {
   5309 				expr->kind = OMINUS;
   5310 				expr->lhs = rhs;
   5311 				deletenode(lhs);
   5312 			}
   5313 		} else if (isvalue(rhs, 0)) {
   5314 			*expr = *lhs;
   5315 			deletenode(lhs); deletenode(rhs);
   5316 		}
   5317 
   5318 		return expr;
   5319 
   5320 	case OMUL: case ODIV: case OMOD:
   5321 		if (lhs->kind == NUMBER && rhs->kind == NUMBER) {
   5322 			if (expr->kind == OMUL) {
   5323 				evalbinary(*);
   5324 			} else  {
   5325 				if (rhs->u.u == 0 && isintorbooltype(ty)) {
   5326 					error(
   5327 						&expr->loc,
   5328 						"division by zero"
   5329 					);
   5330 				} else if (expr->kind == ODIV) {
   5331 					evalbinary(/);
   5332 				} else {
   5333 					/* @todo implement modulus for
   5334 					 *       float-types */
   5335 					evalbinary(/);
   5336 				}
   5337 			}
   5338 		} else if (isvalue(lhs, 0)) {
   5339 			*expr = *lhs;
   5340 			deletenode(lhs);
   5341 			deletenode(rhs);
   5342 		} else if (expr->kind == OMUL && isvalue(rhs, 0)) {
   5343 			*expr = *rhs;
   5344 			deletenode(lhs);
   5345 			deletenode(rhs);
   5346 		} else if (isvalue(rhs, 0)) {
   5347 			if (rhs->u.u == 0 && isintorbooltype(ty))
   5348 				error(&expr->loc, "division by zero");
   5349 			*expr = *rhs;
   5350 			deletenode(lhs);
   5351 			deletenode(rhs);
   5352 		} else if (isvalue(lhs, 1)) {
   5353 			*expr = *rhs;
   5354 			deletenode(lhs);
   5355 			deletenode(rhs);
   5356 		} else if (expr->kind == OMUL && isvalue(rhs, 1)) {
   5357 			*expr = *lhs;
   5358 			deletenode(lhs);
   5359 			deletenode(rhs);
   5360 		}
   5361 
   5362 		return expr;
   5363 
   5364 	case OPLUS:
   5365 		*expr = *lhs;
   5366 
   5367 		deletenode(lhs);
   5368 		return expr;
   5369 
   5370 	case OMINUS:
   5371 		if (lhs->kind == NUMBER) {
   5372 			if (isfloattype(ty)) {
   5373 				expr->kind = NUMBER;
   5374 				expr->u.d = maskfloat(ty->size, -lhs->u.d);
   5375 				deletenode(lhs);
   5376 			} else if (isintorbooltype(ty)) {
   5377 				expr->kind = NUMBER;
   5378 				expr->u.u = maskint(ty->size, -lhs->u.u);
   5379 				deletenode(lhs);
   5380 			}
   5381 		} else if (lhs->kind == OMINUS && lhs->lhs) {
   5382 			*expr = *lhs->lhs;
   5383 			deletenode(lhs);
   5384 		}
   5385 
   5386 		return expr;
   5387 
   5388 	case OBAND: case OBOR: case OXOR:
   5389 		if (lhs->kind == NUMBER && rhs->kind == NUMBER) {
   5390 			assert(isintorbooltype(lhs->type));
   5391 			assert(isintorbooltype(rhs->type));
   5392 			lhs->u.u = maskint(ty->size, lhs->u.u);
   5393 			rhs->u.u = maskint(ty->size, rhs->u.u);
   5394 			if (expr->kind == OBAND)
   5395 				expr->u.u = lhs->u.u & rhs->u.u;
   5396 			else if (expr->kind == OBOR)
   5397 				expr->u.u = lhs->u.u | rhs->u.u;
   5398 			else
   5399 				expr->u.u = lhs->u.u ^ rhs->u.u;
   5400 			expr->kind = NUMBER;
   5401 			expr->u.u = maskint(ty->size, expr->u.u);
   5402 		}
   5403 
   5404 		return expr;
   5405 
   5406 	case ASCOPE:
   5407 		assert(expr->lhs);
   5408 		assert(expr->u.env);
   5409 
   5410 		expr->lhs = foldexpr(expr->u.env, expr->lhs);
   5411 		return expr;
   5412 
   5413 	case ASTMT:
   5414 		rhs = expr;
   5415 	advancestmt:
   5416 		lhs = foldexpr(env, lhs);
   5417 		rhs->lhs = lhs;
   5418 
   5419 		if (rhs->rhs) {
   5420 			assert(rhs->rhs->kind == ASTMT);
   5421 			rhs = rhs->rhs, lhs = rhs->lhs;
   5422 			goto advancestmt;
   5423 		}
   5424 
   5425 		return expr;
   5426 
   5427 	case ACOMPOUND:
   5428 		expr->rhs = foldexpr(env, rhs);
   5429 		return expr;
   5430 
   5431 	case AFIELDINIT:
   5432 		expr->rhs = foldexpr(env, rhs);
   5433 		return expr;
   5434 
   5435 	case ACOMMA:
   5436 		expr->lhs = foldexpr(env, lhs);
   5437 		expr->rhs = foldexpr(env, rhs);
   5438 		return expr;
   5439 
   5440 	case KRETURN:
   5441 		expr->rhs = foldexpr(env, rhs);
   5442 		return expr;
   5443 
   5444 	case KSIZEOF:
   5445 	case KALIGNOF:
   5446 	case KLENGTHOF:
   5447 		assert(lhs);
   5448 
   5449 		expr->lhs = NULL;
   5450 		if (expr->kind == KSIZEOF) {
   5451 			expr->u.u = lhs->type->size;
   5452 
   5453 		} else if (expr->kind == KALIGNOF) {
   5454 			expr->u.u = lhs->type->align;
   5455 
   5456 		} else /* if (expr->kind == KLENGTHOF) */ {
   5457 
   5458 			/* @todo add case for slice */
   5459 			if (lhs->type->kind == TARRAY)
   5460 				expr->u.u = lhs->type->u.array.length;
   5461 			else if (lhs->type->kind == TPTR) {
   5462 				expr->u.u = 1;
   5463 			} else {
   5464 				expr->u.u = 0;
   5465 			}
   5466 		}
   5467 
   5468 		deletenode(lhs);
   5469 		/* @todo delete type */
   5470 		expr->type = prim + TUSIZE;
   5471 		expr->kind = NUMBER;
   5472 		return expr;
   5473 
   5474 	case ACONV:
   5475 		/* @todo implement this properly! */
   5476 		lhs = foldexpr(env, lhs);
   5477 		if (lhs->type->kind == expr->type->kind)
   5478 			*expr = *lhs, deletenode(lhs);
   5479 
   5480 		return expr;
   5481 
   5482 	case ADECL:
   5483 		return folddeclaration(env, expr);
   5484 
   5485 	case TYPE:
   5486 		error(&expr->loc, "exptected expression, not type");
   5487 		/* FALLTHROUGH */
   5488 
   5489 	default:
   5490 		return expr;
   5491 	}
   5492 }
   5493 
   5494 
   5495 
   5496 // }}}
   5497 
   5498 // @section data-flow analysis {{{
   5499 
   5500 /*
   5501 In order to do DFA, we divide the code of a scope into sections.
   5502 For each section there will be a DF-Conduct associated with it.
   5503 
   5504 */
   5505 
   5506 static Block *
   5507 makeblock(BlockKind kind, Env *env)
   5508 {
   5509 	Block *block = myalloc(&env->arenas->block, Block);
   5510 
   5511 	block->kind = kind;
   5512 	block->env  = env;
   5513 
   5514 	return block;
   5515 }
   5516 
   5517 static Conduct *
   5518 makeconduct(Env *env, ConductKind kind, Node *label)
   5519 {
   5520 	Conduct *conduct = myalloc(&env->arenas->conduct, Conduct);
   5521 
   5522 	conduct->kind  = kind;
   5523 	conduct->label = label;
   5524 
   5525 	return conduct;
   5526 }
   5527 
   5528 static void
   5529 transfergists(Env *env, Conduct *source, Conduct *dest);
   5530 
   5531 static void
   5532 appendconduct(Block *parent, ConductKind kind, Node *label)
   5533 {
   5534 	Conduct *conduct = makeconduct(parent->env, kind, label);
   5535 
   5536 	if (!parent)
   5537 		return;
   5538 
   5539 	conduct->parent = parent;
   5540 
   5541 	listappend(parent, conduct);
   5542 
   5543 	if (conduct->prev)
   5544 		transfergists(parent->env, conduct->prev, conduct);
   5545 }
   5546 
   5547 static void
   5548 appendblock(Conduct *parent, BlockKind kind, Env *env)
   5549 {
   5550 	Block *block = makeblock(kind, env);
   5551 
   5552 	appendconduct(block, CSCOPE, NULL);
   5553 
   5554 	if (!parent)
   5555 		return;
   5556 
   5557 	block->parent = parent;
   5558 
   5559 	listappend(parent, block);
   5560 
   5561 	transfergists(env, parent, block->tail);
   5562 }
   5563 
   5564 static Gist *
   5565 makegist(Env *env, Decl *decl, Node *where, bool init)
   5566 {
   5567 	Gist *gist = myalloc(&env->arenas->gist, Gist);
   5568 
   5569 	gist->decl = decl;
   5570 	gist->where = where;
   5571 	gist->init = init;
   5572 
   5573 	return gist;
   5574 }
   5575 
   5576 static void
   5577 appendgist(Conduct *conduct, Gist *info)
   5578 {
   5579 	info->parent = conduct;
   5580 
   5581 	listappendex(conduct, info, gists.head, gists.tail, prev, next);
   5582 }
   5583 
   5584 static void
   5585 transfergists(Env *env, Conduct *source, Conduct *dest)
   5586 {
   5587 	Gist *info;
   5588 
   5589 	for (info = source->gists.head; info; info = info->next) {
   5590 		Gist *copy = makegist(env, NULL, NULL, false);
   5591 
   5592 		*copy = *info;
   5593 
   5594 		appendgist(dest, copy);
   5595 	}
   5596 }
   5597 
   5598 static Gist *
   5599 getgist(Conduct *conduct, Decl *decl)
   5600 {
   5601 	Gist *probe;
   5602 	assert(conduct);
   5603 
   5604 	for (probe = conduct->gists.head; probe; probe = probe->next) {
   5605 		if (probe->decl == decl)
   5606 			return probe;
   5607 	}
   5608 
   5609 	return NULL;
   5610 }
   5611 
   5612 static void
   5613 gistread(Conduct *conduct, Node *node)
   5614 {
   5615 	const char *name;
   5616 	Decl *decl;
   5617 	Gist *info;
   5618 
   5619 	if (!node || (node->kind != ADECLREF && node->kind != ADECL))
   5620 		return;
   5621 
   5622 	decl = node->u.declref;
   5623 
   5624 	/* @note additional checks require that this moves
   5625 	 *              somewhere else. */
   5626 	if ( decl->kind == DPARAM ||
   5627 	    (decl->kind == DVAR   &&
   5628 	     decl->parentenv      &&
   5629 	     decl->parentenv->kind == STOPLEVEL))
   5630 		return;
   5631 
   5632 	name = getstring(idents, decl->key);
   5633 	info = getgist(conduct, decl);
   5634 
   5635 	if (info) {
   5636 		Node *where = info->where;
   5637 
   5638 		if (info->init)
   5639 			return;
   5640 
   5641 		assert(where);
   5642 		error(&node->loc, "use of un-initialized '%s'.", name);
   5643 		/* @todo change to notice or similiar,
   5644 		 *              instead of warn */
   5645 		warn(&where->loc, "last use of '%s' was here.", name);
   5646 	} else {
   5647 		error(&node->loc, "use of un-initialized '%s'.", name);
   5648 	}
   5649 }
   5650 
   5651 static void
   5652 gistwrite(Env *env, Conduct *conduct, Node *node, bool init)
   5653 {
   5654 	Decl *decl;
   5655 	Gist *info;
   5656 
   5657 	if (!node || (node->kind != ADECLREF && node->kind != ADECL))
   5658 		return;
   5659 
   5660 	decl = node->u.declref;
   5661 
   5662 	info = getgist(conduct, decl);
   5663 	if (!info) {
   5664 		info = makegist(env, decl, node, init);
   5665 		appendgist(conduct, info);
   5666 		return;
   5667 	}
   5668 
   5669 	info->init = init;
   5670 	info->where = node;
   5671 }
   5672 
   5673 static void
   5674 fetchblocks(Block *block, Node *expr);
   5675 
   5676 static void
   5677 fetchscoped(Conduct *conduct, Node *expr, BlockKind kind)
   5678 {
   5679 	if (expr && expr->kind == ASCOPE) {
   5680 		appendblock(conduct, kind, expr->u.env);
   5681 		fetchblocks(conduct->tail, expr->lhs);
   5682 
   5683 	} else if (expr) {
   5684 		assert(conduct->parent);
   5685 		assert(conduct->parent->env);
   5686 
   5687 		appendblock(conduct, kind, conduct->parent->env);
   5688 		fetchblocks(conduct->tail, expr);
   5689 	}
   5690 }
   5691 
   5692 static void
   5693 fetchblocks(Block *block, Node *expr)
   5694 {
   5695 	Node *lhs, *rhs;
   5696 
   5697 	assert(expr);
   5698 	assert(block);
   5699 	assert(block->tail);
   5700 
   5701 	lhs = expr->lhs;
   5702 	rhs = expr->rhs;
   5703 
   5704 	switch (expr->kind) {
   5705 	/* unary read */
   5706 	case ODEREF:
   5707 	case OPLUS: case OMINUS:
   5708 	case OBNOT:
   5709 	case OLNOT:
   5710 	case OCAST:
   5711 		fetchblocks(block, lhs);
   5712 		gistread(block->tail, lhs);
   5713 		return;
   5714 
   5715 	/* unary read/write */
   5716 	case OINC: case ODEC:
   5717 	case OSUFINC: case OSUFDEC:
   5718 		fetchblocks(block, lhs);
   5719 		gistread(block->tail, lhs);
   5720 		gistwrite(block->env, block->tail, lhs, true);
   5721 		return;
   5722 
   5723 	/* binary read */
   5724 	case OMUL: case ODIV: case OMOD:
   5725 	case OADD: case OSUB:
   5726 	case OBAND: case OBOR: case OXOR:
   5727 	case OLSH: case ORSH: case OARSH:
   5728 	case OEQU: case ONEQ:
   5729 	case OLET: case OLEQ:
   5730 	case OGRT: case OGEQ:
   5731 	case OLAND: case OLOR:
   5732 		fetchblocks(block, lhs);
   5733 		gistread(block->tail, lhs);
   5734 
   5735 		fetchblocks(block, rhs);
   5736 		gistread(block->tail, rhs);
   5737 		return;
   5738 
   5739 
   5740 	/* binary write */
   5741 	case OASS:
   5742 		fetchblocks(block, rhs);
   5743 		gistread(block->tail, rhs);
   5744 
   5745 		fetchblocks(block, lhs);
   5746 		gistwrite(block->env, block->tail, lhs, true);
   5747 		return;
   5748 
   5749 	/* binary read/write */
   5750 	case OMULA: case ODIVA: case OMODA:
   5751 	case OADDA: case OSUBA:
   5752 	case OLSHA: case ORSHA: case OARSHA:
   5753 	case OANDA:
   5754 	case OORA: case OXORA:
   5755 		fetchblocks(block, rhs);
   5756 		gistread(block->tail, rhs);
   5757 
   5758 		fetchblocks(block, lhs);
   5759 		gistread(block->tail, lhs);
   5760 		gistwrite(block->env, block->tail, lhs, true);
   5761 		return;
   5762 
   5763 	case ASTMT:
   5764 	advancestmt:
   5765 		assert(lhs);
   5766 
   5767 		fetchblocks(block, lhs);
   5768 
   5769 		if (expr->rhs) {
   5770 			assert(expr->rhs->kind == ASTMT);
   5771 			expr = expr->rhs, lhs = expr->lhs;
   5772 			goto advancestmt;
   5773 		}
   5774 		return;
   5775 
   5776 	case ADECL:
   5777 		assert(expr->u.declref);
   5778 		lhs = expr->u.declref->u.content;
   5779 
   5780 		if (expr->u.declref->kind == DFUNCTION) {
   5781 			fetchscoped(block->tail, lhs, BFUNCTION);
   5782 			appendconduct(block, CSCOPE, NULL);
   5783 		} else if (lhs) {
   5784 			appendblock(block->tail, BSCOPE, block->env);
   5785 			fetchblocks(block->tail->tail, lhs);
   5786 			appendconduct(block, CSCOPE, NULL);
   5787 		}
   5788 
   5789 		gistwrite(block->env, block->tail, expr, !!lhs);
   5790 		return;
   5791 
   5792 	case ASCOPE:
   5793 		assert(lhs);
   5794 
   5795 		appendblock(block->tail, BSCOPE, expr->u.env);
   5796 		fetchblocks(block->tail->tail, lhs);
   5797 		appendconduct(block, CSCOPE, NULL);
   5798 		return;
   5799 
   5800 	case ACOMMA:
   5801 		assert(lhs);
   5802 		assert(rhs);
   5803 
   5804 		/* @note is this correct? */
   5805 		fetchblocks(block, lhs);
   5806 		fetchblocks(block, rhs);
   5807 		return;
   5808 
   5809 	case KIF:
   5810 		assert(lhs);
   5811 		assert(expr->u.payload);
   5812 
   5813 		fetchscoped(block->tail, lhs, BIF);
   5814 		if (rhs)
   5815 			fetchscoped(block->tail, rhs, BELSE);
   5816 
   5817 		appendconduct(block, CSCOPE, NULL);
   5818 		return;
   5819 
   5820 	case KDO:
   5821 		return;
   5822 
   5823 	case KLOOP:
   5824 		return;
   5825 
   5826 	case ALOOPUNTIL:
   5827 		return;
   5828 
   5829 	case KBREAK:
   5830 		block->tail->doesbreak = true;
   5831 		goto joinctrltransfer;
   5832 
   5833 	case KCONTINUE:
   5834 		block->tail->doescontinue = true;
   5835 		goto joinctrltransfer;
   5836 
   5837 	case KRETURN:
   5838 		block->tail->doesreturn = true;
   5839 		goto joinctrltransfer;
   5840 
   5841 	case KGOTO:
   5842 		block->tail->doesjump = true;
   5843 	joinctrltransfer:
   5844 		appendconduct(block, CUNREACH, NULL);
   5845 		return;
   5846 
   5847 	default:
   5848 	case OADDR:
   5849 		return;
   5850 	}
   5851 }
   5852 
   5853 #if 0
   5854 static void
   5855 debugprintconduct(Conduct *conduct, int indent);
   5856 
   5857 static void
   5858 debugprintblock(Block *block, int indent)
   5859 {
   5860 	Block *curr;
   5861 	assert(block);
   5862 
   5863 	for (curr = block; curr; curr = curr->next) {
   5864 		int i;
   5865 
   5866 		for (i = 0; i < indent; ++i) {
   5867 			printf("\t");
   5868 		}
   5869 
   5870 		switch (curr->kind) {
   5871 		case BTOPLEVEL: printf("\x1b[31mblock<toplevel>\x1b[0m\n"); break;
   5872 		case BFUNCTION: printf("\x1b[31mblock<function>\x1b[0m\n"); break;
   5873 		case BSCOPE: printf("\x1b[31mblock<scope>\x1b[0m\n"); break;
   5874 		case BIF: printf("\x1b[31mblock<if>\x1b[0m\n"); break;
   5875 		case BLOOP: printf("\x1b[31mblock<loop>\x1b[0m\n"); break;
   5876 		case BWHILELOOP: printf("\x1b[31mblock<while-loop>\x1b[0m\n"); break;
   5877 		case BLOOPUNTIL: printf("\x1b[31mblock<loop-until>\x1b[0m\n"); break;
   5878 		case BFORLOOP: printf("\x1b[31mblock<for-loop>\x1b[0m\n"); break;
   5879 		case BELSE: printf("\x1b[31mblock<else>\x1b[0m\n"); break;
   5880 		}
   5881 
   5882 		if (curr->head)
   5883 			debugprintconduct(curr->head, indent);
   5884 	}
   5885 }
   5886 
   5887 static void
   5888 debugprintconduct(Conduct *conduct, int indent)
   5889 {
   5890 	Conduct *curr;
   5891 	assert(conduct);
   5892 
   5893 	for (curr = conduct; curr; curr = curr->next) {
   5894 		int i;
   5895 
   5896 		for (i = 0; i < indent; ++i) {
   5897 			printf("\t");
   5898 		}
   5899 
   5900 		switch (curr->kind) {
   5901 		case CUNREACH: printf("\x1b[34mconduct<unreach>\x1b[0m\n"); break;
   5902 		case CSCOPE: printf("\x1b[34mconduct<scope>\x1b[0m\n"); break;
   5903 		case CLABEL: printf("\x1b[34mconduct<label>\x1b[0m\n"); break;
   5904 		case CBLOCK:
   5905 			break;
   5906 		}
   5907 
   5908 		if (curr->head)
   5909 			debugprintblock(curr->head, indent + 1);
   5910 	}
   5911 }
   5912 #else
   5913 static void
   5914 debugprintblock(Block *block, int indent)
   5915 {
   5916 	(void) block;
   5917 	(void) indent;
   5918 }
   5919 #endif
   5920 
   5921 static void
   5922 dataflow(Block *block, Node *expr)
   5923 {
   5924 	assert(expr);
   5925 
   5926 	fetchblocks(block, expr);
   5927 
   5928 	debugprintblock(block, 0);
   5929 }
   5930 
   5931 
   5932 
   5933 /* @section data-flow analysis version 2 */
   5934 
   5935 #if 0
   5936 
   5937 static void
   5938 fetchsections(Analysis *analysis, Node *expr)
   5939 {
   5940 	Node *lhs, *rhs;
   5941 
   5942 nextnode:
   5943 	switch (expr->kind) {
   5944 	default:
   5945 		break;
   5946 	}
   5947 }
   5948 
   5949 static void
   5950 dataflow2(Analysis *analysis, Node *expr)
   5951 {
   5952 	assert(expr);
   5953 
   5954 	fetchsections(analysis, expr);
   5955 }
   5956 
   5957 #endif
   5958 
   5959 
   5960 
   5961 // }}}
   5962 
   5963 
   5964 // @section extract nested functions {{{
   5965 
   5966 Node *extracted[1024 * 4];
   5967 int extractedtop = 0;
   5968 
   5969 static bool
   5970 isnestedfunction(Env *startenv)
   5971 {
   5972 	Env *env;
   5973 	int n = 0;
   5974 
   5975 	for (env = startenv; env; env = env->below) {
   5976 		if (env->kind == SFUNCTION)
   5977 			++n;
   5978 	}
   5979 	
   5980 	return n > 1;
   5981 }
   5982 
   5983 static void
   5984 extractnfs(Env *env, Node *expr);
   5985 
   5986 static void
   5987 substituenfs(Env *env, Node *expr)
   5988 {
   5989 	Decl *decl = expr->u.declref;
   5990 	Node *enlist = NULL;
   5991 
   5992 	assert(decl);
   5993 
   5994 	if (decl->u.content) {
   5995 		env = decl->contentenv ? decl->contentenv : env;
   5996 		extractnfs(env, decl->u.content);
   5997 	}
   5998 
   5999 	if (decl->kind == DFUNCTION && isnestedfunction(decl->contentenv)) {
   6000 		enlist = makenode(env->arenas, expr, NULL);
   6001 		expr->kind = ADECLREF;
   6002 
   6003 		assert(extractedtop < lengthof(extracted));
   6004 		extracted[extractedtop++] = enlist;
   6005 	}
   6006 }
   6007 
   6008 static void
   6009 extractnfs(Env *env, Node *expr)
   6010 {
   6011 advance:
   6012 	assert(expr);
   6013 
   6014 	if (isoperator(expr->kind)) {
   6015 		switch (getnumops(expr->kind)) {
   6016 		case 3:
   6017 			assert(expr->u.payload);
   6018 			extractnfs(env, expr->u.payload);
   6019 			/* FALLTHROUGH */
   6020 		case 2:
   6021 			assert(expr->rhs);
   6022 			extractnfs(env, expr->rhs);
   6023 			/* FALLTHROUGH */
   6024 		case 1:
   6025 			assert(expr->lhs);
   6026 			extractnfs(env, expr->lhs);
   6027 		}
   6028 		return;
   6029 	}
   6030 
   6031 	switch (expr->kind) {
   6032 	case KRETURN:
   6033 	case KIF:
   6034 	case KCASE:
   6035 	case KOF:
   6036 	case KDO:
   6037 	case KFOR:
   6038 	case KLOOP:
   6039 	case KWHILE:
   6040 	case KUNTIL:
   6041 	case AFORSTEP:
   6042 	case AFOREACH:
   6043 	case ALOOPUNTIL:
   6044 		if (expr->u.payload)
   6045 			extractnfs(env, expr->u.payload);
   6046 		if (expr->lhs)
   6047 			extractnfs(env, expr->lhs);
   6048 		if (expr->rhs) 
   6049 			extractnfs(env, expr->rhs);
   6050 		break;
   6051 	case ADEREF:
   6052 	case ACONV:
   6053 	case ASELFDISP:
   6054 		assert(expr->lhs);
   6055 		extractnfs(env, expr->lhs);
   6056 		break;
   6057 	case ACOMMA:
   6058 		assert(expr->lhs);
   6059 		assert(expr->rhs);
   6060 		extractnfs(env, expr->lhs);
   6061 		extractnfs(env, expr->rhs);
   6062 		break;
   6063 	case ASTMT:
   6064 		assert(expr->lhs);
   6065 		extractnfs(env, expr->lhs);
   6066 		if (expr->rhs) {
   6067 			expr = expr->rhs;
   6068 			goto advance;
   6069 		}
   6070 		break;
   6071 	case ADECL:
   6072 		substituenfs(env, expr);
   6073 		break;
   6074 	case AENV:
   6075 	case ASCOPE:
   6076 		assert(expr->lhs);
   6077 		assert(expr->u.env);
   6078 		extractnfs(expr->u.env, expr->lhs);
   6079 		break;
   6080 	case TYPE: /* @note is this correct? */
   6081 	case CHAR:
   6082 	case NUMBER:
   6083 	case STRING:
   6084 	case ADECLREF:
   6085 	case IDENT: /* @note is this correct? */
   6086 		break;
   6087 
   6088 	case ACOMPOUND:
   6089 		/* @todo extract within type (lhs)? */
   6090 		assert(expr->rhs);
   6091 		extractnfs(env, expr->lhs);
   6092 		break;
   6093 	
   6094 	case AFIELDINIT:
   6095 		assert(expr->rhs);
   6096 		extractnfs(env, expr->rhs);
   6097 		break;
   6098 
   6099 	case KSTRUCT:
   6100 	case KUNION:
   6101 		assert(expr->rhs);
   6102 		extractnfs(env, expr->rhs);
   6103 		break;
   6104 
   6105 	case KBREAK:
   6106 	case KCONTINUE:
   6107 	case KGOTO:
   6108 		break;
   6109 
   6110 	case KSIZEOF:
   6111 	case KALIGNOF:
   6112 		/* @todo check for nested functions and report error */
   6113 		break;
   6114 
   6115 	default:
   6116 		error(&expr->loc, "internal error: unknown expression kind"
   6117 			" (%s).", nodestrings[expr->kind]);
   6118 		break;
   6119 	}
   6120 }
   6121 
   6122 static Node *
   6123 extractnestedfunctions(Env *env, Node *expr)
   6124 {
   6125 	extractedtop = 0;
   6126 
   6127 	extractnfs(env, expr);
   6128 
   6129 	assert(extractedtop < lengthof(extracted));
   6130 	extracted[extractedtop++] = expr;
   6131 	return expr;
   6132 }
   6133 
   6134 // }}}
   6135 
   6136 // @section c code generation {{{
   6137 
   6138 static void
   6139 codegen(CodeGen *cg, Node *expr);
   6140 
   6141 static void
   6142 cgindent(CodeGen *cg)
   6143 {
   6144 	int i;
   6145 
   6146 	for (i = 0; i < cg->indent; ++i) {
   6147 		fprintf(cg->out, "\t");
   6148 	}
   6149 }
   6150 
   6151 static void
   6152 cgprintf(CodeGen *cg, const char *fmt, ...)
   6153 {
   6154 	va_list ap;
   6155 
   6156 	(void) cg;
   6157 	va_start(ap, fmt);
   6158 	vfprintf(cg->out, fmt, ap);
   6159 	va_end(ap);
   6160 }
   6161 
   6162 static void
   6163 cginit(CodeGen *cg, FILE *out)
   6164 {
   6165 	cg->out = out;
   6166 	cg->indent = 0;
   6167 	cg->commacount = 0;
   6168 	cg->needsvalue = false;
   6169 	cg->hasclause = false;
   6170 	cg->valuename = NULL;
   6171 
   6172 	assert(cg->out);
   6173 
   6174 	cgprintf(cg, "#include <assert.h>\n");
   6175 	cgprintf(cg, "#include <stdarg.h>\n");
   6176 	cgprintf(cg, "#include <stdbool.h>\n");
   6177 	cgprintf(cg, "#include <stdint.h>\n");
   6178 	cgprintf(cg, "#include <stdio.h>\n");
   6179 	cgprintf(cg, "#include <stdlib.h>\n");
   6180 	cgprintf(cg, "#include <string.h>\n");
   6181 
   6182 	cgprintf(cg, "typedef unsigned char uchar;\n");
   6183 	cgprintf(cg, "typedef unsigned uint;\n");
   6184 
   6185 	cgprintf(cg, "typedef int16_t s16;\n");
   6186 	cgprintf(cg, "typedef uint16_t u16;\n");
   6187 	cgprintf(cg, "typedef unsigned int uint;\n");
   6188 	cgprintf(cg, "typedef int64_t s64;\n");
   6189 	cgprintf(cg, "typedef uint64_t u64;\n");
   6190 
   6191 	cgprintf(cg, "\n");
   6192 }
   6193 
   6194 static void
   6195 cgtype(CodeGen *cg, Type *type, Decl *decl);
   6196 
   6197 static void
   6198 cgforward(Source *source, Node *ast, CodeGen *cg)
   6199 {
   6200 	Decl *decl;
   6201 	assert(ast->kind == ADECL);
   6202 
   6203 	decl = ast->u.declref;
   6204 	if (decl->kind == DFUNCTION) {
   6205 		cgtype(cg, ast->type, decl);
   6206 
   6207 	} else if (decl->kind == DVAR) {
   6208 		/* @todo check storage class before using extern */
   6209 		cgprintf(cg, "extern ");
   6210 		cgtype(cg, ast->type, decl);
   6211 
   6212 		/* @todo implement variable forward declaration */
   6213 	} else {
   6214 		assert(!"never reach here");
   6215 	}
   6216 }
   6217 
   6218 static void
   6219 cgtoplevel(Source *source, Node *ast, CodeGen *cg)
   6220 {
   6221 	if (source->haspendingenv) {
   6222 		assert(source->pendingcount < 512);
   6223 		source->pendingnodes[source->pendingcount++] = ast;
   6224 		source->haspendingenv = false;
   6225 
   6226 		/* @todo forwad declarations of nested function, etc.
   6227 		 *       may also be needed */
   6228 		cgforward(source, ast, cg);
   6229 		cgprintf(cg, ";\n");
   6230 	} else {
   6231 		codegen(cg, ast);
   6232 		if (ast->kind != ADECL || ast->u.declref->kind != DFUNCTION)
   6233 			cgprintf(cg, ";\n");
   6234 		else
   6235 			cgprintf(cg, "\n");
   6236 		/* deletenode(ast); */
   6237 	}
   6238 }
   6239 
   6240 static void
   6241 cgtoplevelfinish(Source *source, CodeGen *cg)
   6242 {
   6243 	int i;
   6244 
   6245 	for (i = 0; i < source->pendingcount; ++i) {
   6246 		Node *ast = source->pendingnodes[i];
   6247 
   6248 		codegen(cg, ast);
   6249 		if (ast->kind != ADECL || ast->u.declref->kind != DFUNCTION)
   6250 			cgprintf(cg, ";\n");
   6251 		else
   6252 			cgprintf(cg, "\n");
   6253 		/* deletenode(ast); */
   6254 	}
   6255 }
   6256 
   6257 #if 0
   6258 static void
   6259 cgtypetail(CodeGen *cg, Type *type)
   6260 {
   6261 	if (!type)
   6262 		return;
   6263 
   6264 	if (type->kind == TFUNCTION) {
   6265 		cgtypetail(cg, type->u.rtarget);
   6266 		cgprintf(cg, " function(");
   6267 		if (type->target)
   6268 			cgtypetail(cg, type->target);
   6269 		cgprintf(cg, ")");
   6270 		return;
   6271 	}
   6272 
   6273 	if (type->kind != TTUPLE && type->target &&
   6274 	    type->target->kind == TTUPLE)
   6275 	{
   6276 		cgprintf(cg, "(");
   6277 		cgtypetail(cg, type->target);
   6278 		cgprintf(cg, ")");
   6279 	} else {
   6280 		cgtypetail(cg, type->target);
   6281 	}
   6282 
   6283 	if (type->module) {
   6284 		cgprintf(cg, "%s", getstring(idents, type->module->key));
   6285 		return;
   6286 	}
   6287 
   6288 	switch (type->kind) {
   6289 	case TARRAY:
   6290 		cgprintf(cg, "[");
   6291 
   6292 		/* @note the value may be always set in the future */
   6293 		if (type->u.val)
   6294 			codegen(cg, type->u.val);
   6295 
   6296 		cgprintf(cg, "]");
   6297 		break;
   6298 
   6299 	case TTUPLE:
   6300 		cgprintf(cg, ", ");
   6301 		if (type->u.rtarget && type->u.rtarget->kind == TTUPLE) {
   6302 			cgprintf(cg, "(");
   6303 			cgtypetail(cg, type->u.rtarget);
   6304 			cgprintf(cg, ")");
   6305 		} else {
   6306 			cgtypetail(cg, type->u.rtarget);
   6307 		}
   6308 
   6309 		break;
   6310 
   6311 	default:;
   6312 	}
   6313 
   6314 	return;
   6315 }
   6316 
   6317 static void
   6318 cgbasetype(CodeGen *cg, Type *type)
   6319 {
   6320 	while (type->target)
   6321 		type = type->target;
   6322 
   6323 	switch (type->kind) {
   6324 	#define typecase(type, str) \
   6325 		case type: cgprintf(cg, str); break
   6326 	typecase(TERRTYPE,   "<error-type>");
   6327 	typecase(TUNDEFINED, "<undefined-type>");
   6328 	typecase(TPTR,       "*");
   6329 	typecase(TVOID,      "void" ); typecase(TBOOL,   "bool"  );
   6330 	typecase(TINFER,     "infer"); typecase(TUINFER, "uinfer");
   6331 	typecase(TS8,        "char" ); typecase(TU8,     "uchar" );
   6332 	typecase(TS16,       "s16"  ); typecase(TU16,    "u16"   );
   6333 	typecase(TS32,       "int"  ); typecase(TU32,    "uint"  );
   6334 	typecase(TS64,       "s64"  ); typecase(TU64,    "u64"   );
   6335 	typecase(TF32,       "float"); typecase(TF64,    "double");
   6336 	#undef typecase
   6337 	default:
   6338 		cgprintf(cg, "<unknown-type-%d>", type->kind);
   6339 	}
   6340 }
   6341 #endif
   6342 
   6343 static void
   6344 cgnamedparams(CodeGen *cg, Decl *decl)
   6345 {
   6346 	Decl *param, *head = NULL;
   6347 
   6348 	cgprintf(cg, "(");
   6349 
   6350 	if (decl->contentenv) {
   6351 		head = decl->contentenv->head;
   6352 	}
   6353 
   6354 	for (param = head; param; param = param->next) {
   6355 		if (param->kind != DPARAM)
   6356 			break;
   6357 
   6358 		if (param != head) {
   6359 			cgprintf(cg, ", ");
   6360 		}
   6361 
   6362 		++cg->indent;
   6363 		cgtype(cg, param->type, param);
   6364 		--cg->indent;
   6365 	}
   6366 
   6367 	cgprintf(cg, ")");
   6368 }
   6369 
   6370 static void
   6371 cgdeclmodule(CodeGen *cg, Decl *module)
   6372 {
   6373 	if (module->module)
   6374 		cgdeclmodule(cg, module->module);
   6375 
   6376 	cgprintf(cg, "%s_", getstring(idents, module->key));
   6377 }
   6378 
   6379 static void
   6380 cgdeclname(CodeGen *cg, Decl *decl)
   6381 {
   6382 	if (decl->module)
   6383 		cgdeclmodule(cg, decl->module);
   6384 
   6385 	cgprintf(cg, "%s", getstring(idents, decl->key));
   6386 }
   6387 
   6388 static void
   6389 cgbasetype(CodeGen *cg, Type *type)
   6390 {
   6391 	switch (type->kind) {
   6392 	#define typecase(type, str) \
   6393 		case type: cgprintf(cg, str); break
   6394 	typecase(TERRTYPE,   "<error-type>");
   6395 	typecase(TUNDEFINED, "<undefined-type>");
   6396 	typecase(TPTR,       "*");
   6397 	typecase(TVOID,      "void" ); typecase(TBOOL,   "bool"  );
   6398 	typecase(TINFER,     "infer"); typecase(TUINFER, "uinfer");
   6399 	typecase(TS8,        "char" ); typecase(TU8,     "uchar" );
   6400 	typecase(TS16,       "s16"  ); typecase(TU16,    "u16"   );
   6401 	typecase(TS32,       "int"  ); typecase(TU32,    "uint"  );
   6402 	typecase(TS64,       "s64"  ); typecase(TU64,    "u64"   );
   6403 	typecase(TF32,       "float"); typecase(TF64,    "double");
   6404 	#undef typecase
   6405 
   6406 	case TUNION:
   6407 		cgprintf(cg, "union ");
   6408 		goto joinstruct;
   6409 
   6410 	case TSTRUCT:
   6411 		cgprintf(cg, "struct ");
   6412 	joinstruct:
   6413 		assert(type->module);
   6414 		cgdeclname(cg, type->module);
   6415 		break;
   6416 
   6417 	default:
   6418 		cgprintf(cg, "<unknown-type-%d>", type->kind);
   6419 	}
   6420 }
   6421 
   6422 static void
   6423 cgtype(CodeGen *cg, Type *type, Decl *decl)
   6424 {
   6425 	Type *stack[64];
   6426 	Type *post[64];
   6427 	int top = 0, pcount = 0;
   6428 
   6429 	if (isrecordenv(cg->env) && type->kind == TFUNCTION) {
   6430 		assert(top < lengthof(stack));
   6431 		stack[top++] = maketype(
   6432 			cg->env->arenas, &decl->loc, 
   6433 			primitive(TPTR), type);
   6434 	}
   6435 
   6436 	while (type->target || type->kind == TFUNCTION) {
   6437 		assert(top < lengthof(stack));
   6438 		stack[top++] = type;
   6439 		if (type->kind == TFUNCTION) {
   6440 			assert(type->u.rtarget);
   6441 			type = type->u.rtarget;
   6442 		} else {
   6443 			type = type->target;
   6444 		}
   6445 	}
   6446 
   6447 	if (cg->commacount)
   6448 		goto decorate;
   6449 
   6450 	cgbasetype(cg, type);
   6451 	cgprintf(cg, " ");
   6452 
   6453 decorate:
   6454 	while (top > 0) {
   6455 		Type *curr = stack[--top];
   6456 		if (curr->kind == TPTR) {
   6457 			Type *target = curr->target;
   6458 			if (target->kind != TPTR && (target->target || target->u.rtarget)) {
   6459 				cgprintf(cg, "(*");
   6460 				assert(pcount < lengthof(post));
   6461 				post[pcount++] = curr;
   6462 			} else {
   6463 				cgprintf(cg, "*");
   6464 			}
   6465 #if 0
   6466 			if (target->isconst)
   6467 				cgprintf(cg, "const ");
   6468 #endif
   6469 		} else {
   6470 			assert(pcount < lengthof(post));
   6471 			post[pcount++] = curr;
   6472 		}
   6473 	}
   6474 
   6475 	if (decl) {
   6476 		if (isrecordenv(cg->env))
   6477 			cgprintf(cg, "%s", getstring(idents, decl->key));
   6478 		else
   6479 			cgdeclname(cg, decl);
   6480 	}
   6481 
   6482 
   6483 	while (pcount > 0) {
   6484 		Type *curr = post[--pcount];
   6485 		switch (curr->kind) {
   6486 		case TPTR:
   6487 			cgprintf(cg, ")");
   6488 			continue;
   6489 		case TARRAY:
   6490 			cgprintf(cg, "[");
   6491 			codegen(cg, curr->u.val);
   6492 			cgprintf(cg, "]");
   6493 			continue;
   6494 		case TFUNCTION:
   6495 			if (decl && decl->kind == DFUNCTION) {
   6496 				/* print named or empty parameter list */
   6497 				cgnamedparams(cg, decl);
   6498 				/* Only the innermost function is referred
   6499 				 * by decl. So we can set decl to NULL. */
   6500 				decl = NULL;
   6501 			} else if (curr->target
   6502 			       &&  curr->target->kind == TTUPLE) {
   6503 				Type *tuple = curr->target;
   6504 				/* print anonymous parameter list */
   6505 				cgprintf(cg, "(");
   6506 				for (;;) {
   6507 					assert(tuple->target);
   6508 					cgtype(cg, tuple->target, NULL);
   6509 					cgprintf(cg, ", ");
   6510 
   6511 					assert(tuple->u.rtarget);
   6512 					tuple = tuple->u.rtarget;
   6513 					if (tuple->kind != TTUPLE) {
   6514 						cgtype(cg, tuple, NULL);
   6515 						break;
   6516 					}
   6517 				}
   6518 				cgprintf(cg, ")");
   6519 			} else {
   6520 				/* print empty parameter list */
   6521 				cgprintf(cg, "()");
   6522 			}
   6523 		default:
   6524 			continue;
   6525 		}
   6526 	}
   6527 }
   6528 
   6529 static void
   6530 cgnumber(CodeGen *cg, Node *expr)
   6531 {
   6532 	switch (expr->type->kind) {
   6533 	case TF32: case TF64:
   6534 	/* case TLDOUBLE: */
   6535 		cgprintf(cg, "%f", expr->u.d);
   6536 		if (expr->type->kind == TF32)
   6537 			cgprintf(cg, "f");
   6538 		break;
   6539 
   6540 	case TINFER:
   6541 	case TS8:  case TS16: case TS32: case TS64:
   6542 		cgprintf(cg, "%lli", expr->u.s);
   6543 		break;
   6544 
   6545 	case TUINFER:
   6546 	case TU8:  case TU16: case TU32: case TU64:
   6547 		cgprintf(cg, "%llu", expr->u.s);
   6548 		break;
   6549 
   6550 	case TBOOL:
   6551 		if (expr->u.u == 0)
   6552 			cgprintf(cg, "false");
   6553 		else if (expr->u.u == 1)
   6554 			cgprintf(cg, "true");
   6555 		else
   6556 			cgprintf(cg, "((bool) 0x%016llx)", expr->u.u);
   6557 		break;
   6558 
   6559 	case TPTR:
   6560 		if (expr->u.u == 0)
   6561 			cgprintf(cg, "NULL");
   6562 		else
   6563 			cgprintf(cg, "((void *) 0x%016llx)", expr->u.u);
   6564 		break;
   6565 
   6566 	case TVOID:
   6567 	default:
   6568 		cgprintf(cg, "---");
   6569 		break;
   6570 
   6571 	}
   6572 
   6573 }
   6574 
   6575 static void
   6576 cgmapchar(CodeGen *cg, char ch)
   6577 {
   6578 	#define mapchar(from, to) \
   6579 		case from: cgprintf(cg, to); return
   6580 	switch (ch) {
   6581 	mapchar('\\', "\\\\");
   6582 	mapchar('\"', "\\\"");
   6583 	mapchar('\'', "\\\'");
   6584 	mapchar('\n', "\\n");
   6585 	mapchar('\t', "\\t");
   6586 	mapchar('\r', "\\r");
   6587 	mapchar('\b', "\\b");
   6588 	mapchar('\f', "\\f");
   6589 	mapchar('\v', "\\v");
   6590 	mapchar('\0', "\\0");
   6591 	default:
   6592 		if (ch < 32 || (uint8_t) ch >= 127)
   6593 			cgprintf(cg, "\\x%02x", (uint8_t) ch);
   6594 		else
   6595 			cgprintf(cg, "%c", ch);
   6596 		break;
   6597 	}
   6598 	#undef mapchar
   6599 }
   6600 
   6601 static void
   6602 cgdeclaration(CodeGen *cg, Node *expr)
   6603 {
   6604 	Decl *decl = expr->u.declref;
   6605 
   6606 	assert(decl);
   6607 	assert(expr->type);
   6608 
   6609 	cgtype(cg, expr->type, decl);
   6610 
   6611 	if (decl->kind == DFUNCTION) {
   6612 		if (!decl->u.content)
   6613 			return;
   6614 
   6615 		cgprintf(cg, "\n");
   6616 		cgindent(cg);
   6617 		cgprintf(cg, "{\n");
   6618 		
   6619 		++cg->indent;
   6620 		codegen(cg, decl->contentenv->stmts);
   6621 		--cg->indent;
   6622 		
   6623 		cgindent(cg);
   6624 		cgprintf(cg, "}\n");
   6625 		cg->hasclause = true;
   6626 	} else if (decl->kind == DPARAM || decl->kind == DVAR) {
   6627 		if (isrecordenv(decl->parentenv))
   6628 			return;
   6629 
   6630 		if (decl->u.content) {
   6631 			cgprintf(cg, " = ");
   6632 			codegen(cg, decl->u.content);
   6633 		}
   6634 	}
   6635 }
   6636 
   6637 static void
   6638 cgsubexpr(CodeGen *cg, Node *expr)
   6639 {
   6640 	if (isatomnode(expr->kind)) {
   6641 		codegen(cg, expr);
   6642 		return;
   6643 	}
   6644 
   6645 	cgprintf(cg, "(");
   6646 	codegen(cg, expr);
   6647 	cgprintf(cg, ")");
   6648 }
   6649 
   6650 static void
   6651 cgunaryprefixop(CodeGen *cg, Node *expr, const char *op)
   6652 {
   6653 	cgprintf(cg, "%s", op);
   6654 	cgsubexpr(cg, expr->lhs);
   6655 }
   6656 
   6657 static void
   6658 cgbinaryop(CodeGen *cg, Node *expr, const char *op)
   6659 {
   6660 	cgsubexpr(cg, expr->lhs);
   6661 	cgprintf(cg, " %s ", op);
   6662 	cgsubexpr(cg, expr->rhs);
   6663 }
   6664 
   6665 static void
   6666 cgprintclause(CodeGen *cg, Node *clause)
   6667 {
   6668 	cgprintf(cg, " {\n");
   6669 	++cg->indent;
   6670 	codegen(cg, clause);
   6671 	--cg->indent;
   6672 	cgindent(cg);
   6673 	cgprintf(cg, "}");
   6674 	cg->hasclause = true;
   6675 }
   6676 
   6677 static void
   6678 codegen(CodeGen *cg, Node *expr)
   6679 {
   6680 	assert(expr);
   6681 
   6682 	switch (expr->kind) {
   6683 	case IDENT:
   6684 		cgprintf(cg, "%s", getstring(idents, expr->u.key));
   6685 		break;
   6686 	case CHAR:
   6687 		cgprintf(cg, "'");
   6688 		cgmapchar(cg, (uchar) expr->u.u);
   6689 		cgprintf(cg, "'");
   6690 		break;
   6691 	case TYPE:
   6692 		break;
   6693 	case NUMBER:
   6694 		cgnumber(cg, expr);
   6695 		break;
   6696 	case STRING:
   6697 		cgprintf(cg, "\"");
   6698 		do {
   6699 			const int length = getlength(strings, expr->u.key);
   6700 			const char *string = getstring(strings, expr->u.key);
   6701 
   6702 			int i;
   6703 
   6704 			/* @note string must have at least one char
   6705 			 * (null-char at the end) which is not printed */
   6706 			assert(length);
   6707 			for (i = 0; i < length - 1; ++i) {
   6708 				cgmapchar(cg, string[i]);
   6709 			}
   6710 		} while (0);
   6711 		cgprintf(cg, "\"");
   6712 		break;
   6713 	case ACOMPOUND:
   6714 		cgprintf(cg, "((");
   6715 		cgbasetype(cg, expr->type);
   6716 		cgprintf(cg, ") {");
   6717 		++cg->indent;
   6718 		codegen(cg, expr->rhs);
   6719 		--cg->indent;
   6720 		cgindent(cg);
   6721 		cgprintf(cg, "})");
   6722 		break;
   6723 	case AFIELDINIT:
   6724 		codegen(cg, expr->rhs);
   6725 		break;
   6726 	case KTRUE:
   6727 		cgprintf(cg, "true");
   6728 		break;
   6729 	case KFALSE:
   6730 		cgprintf(cg, "false");
   6731 		break;
   6732 	case KNULL:
   6733 		cgprintf(cg, "NULL");
   6734 		break;
   6735 	case KSIZEOF:
   6736 		/* @todo consider dynamic arrays? */
   6737 		cgprintf(cg, "(%zu)", expr->type->size);
   6738 		break;
   6739 	case KALIGNOF:
   6740 		cgprintf(cg, "(%zu)", expr->type->align);
   6741 		break;
   6742 	case KLENGTHOF:
   6743 		/* @todo implement lengthof */
   6744 		break;
   6745 	case ADECLREF:
   6746 		cgdeclname(cg, expr->u.declref);
   6747 		break;
   6748 	case ALABEL:
   6749 	case ASWITCH:
   6750 	case ACASE:
   6751 		break;
   6752 	case ACONV:
   6753 		codegen(cg, expr->lhs);
   6754 		break;
   6755 	case KDO:
   6756 		/* @todo implement c version correctly */
   6757 	case ASCOPE:
   6758 		do {
   6759 			Env *env = cg->env;
   6760 			Node *curr = expr->lhs;
   6761 			if (expr->u.env)
   6762 				cg->env = expr->u.env;
   6763 			while (curr) {
   6764 				cgindent(cg);
   6765 				codegen(cg, curr);
   6766 				if (curr->kind == ASTMT)
   6767 					curr = curr->rhs;
   6768 				else
   6769 					break;
   6770 			}
   6771 			cg->env = env;
   6772 		} while (0);
   6773 		break;
   6774 	case AENV:
   6775 		assert(expr->lhs);
   6776 		codegen(cg, expr->lhs);
   6777 		break;
   6778 	case ASTMT:
   6779 		cg->hasclause = false;
   6780 		codegen(cg, expr->lhs);
   6781 		if (!cg->hasclause)
   6782 			cgprintf(cg, "; /* statement */\n");
   6783 		cg->hasclause = false;
   6784 		break;
   6785 	case ADECL:
   6786 		cgdeclaration(cg, expr);
   6787 		break;
   6788 	case OSUFINC:
   6789 		cgsubexpr(cg, expr->lhs);
   6790 		cgprintf(cg, "++");
   6791 		break;
   6792 	case OSUFDEC:
   6793 		cgsubexpr(cg, expr->lhs);
   6794 		cgprintf(cg, "++");
   6795 		break;
   6796 	case OARRAY:
   6797 		cgsubexpr(cg, expr->lhs);
   6798 		cgprintf(cg, "[");
   6799 		codegen(cg, expr->rhs);
   6800 		cgprintf(cg, "]");
   6801 		break;
   6802 	case ODISP:
   6803 		cgsubexpr(cg, expr->lhs);
   6804 		cgprintf(cg, ".");
   6805 		codegen(cg, expr->rhs);
   6806 		break;
   6807 	case OCALL:
   6808 		cgsubexpr(cg, expr->lhs);
   6809 		cgprintf(cg, "(");
   6810 		if (expr->rhs)
   6811 			codegen(cg, expr->rhs);
   6812 		cgprintf(cg, ")");
   6813 		break;
   6814 	case OADDR:
   6815 	case AADDR:
   6816 		cgunaryprefixop(cg, expr, "&");
   6817 		break;
   6818 	case ODEREF:
   6819 	case ADEREF:
   6820 		cgunaryprefixop(cg, expr, "*");
   6821 		break;
   6822 	case OINC:
   6823 		cgunaryprefixop(cg, expr, "++");
   6824 		break;
   6825 	case ODEC:
   6826 		cgunaryprefixop(cg, expr, "--");
   6827 		break;
   6828 	case OBNOT:
   6829 		cgunaryprefixop(cg, expr, "~");
   6830 		break;
   6831 	case OLNOT:
   6832 		cgunaryprefixop(cg, expr, "!");
   6833 		break;
   6834 	case OPLUS:
   6835 		cgunaryprefixop(cg, expr, "+");
   6836 		break;
   6837 	case OMINUS:
   6838 		cgunaryprefixop(cg, expr, "-");
   6839 		break;
   6840 	case OCAST:
   6841 		/* @todo implement c version correctly */
   6842 		cgprintf(cg, "(");
   6843 		codegen(cg, expr->lhs);
   6844 		cgprintf(cg, ")");
   6845 		break;
   6846 	case OMUL:
   6847 		cgbinaryop(cg, expr, "*");
   6848 		break;
   6849 	case ODIV:
   6850 		cgbinaryop(cg, expr, "/");
   6851 		break;
   6852 	case OMOD:
   6853 		cgbinaryop(cg, expr, "%");
   6854 		break;
   6855 	case OBAND:
   6856 		cgbinaryop(cg, expr, "&");
   6857 		break;
   6858 	case OLSH:
   6859 		cgbinaryop(cg, expr, "<<");
   6860 		break;
   6861 	case OARSH:
   6862 		/* @todo implement c version correctly */
   6863 		cgbinaryop(cg, expr, ">>>");
   6864 		break;
   6865 	case ORSH:
   6866 		cgbinaryop(cg, expr, ">>");
   6867 		break;
   6868 	case OADD:
   6869 		cgbinaryop(cg, expr, "+");
   6870 		break;
   6871 	case OSUB:
   6872 		cgbinaryop(cg, expr, "-");
   6873 		break;
   6874 	case OBOR:
   6875 		cgbinaryop(cg, expr, "|");
   6876 		break;
   6877 	case OXOR:
   6878 		cgbinaryop(cg, expr, "^");
   6879 		break;
   6880 	case OFLIP:
   6881 	case ORANGE:
   6882 		/* @todo implement c version correctly */
   6883 		cgbinaryop(cg, expr, "~");
   6884 		break;
   6885 	case OLEQ:
   6886 		cgbinaryop(cg, expr, "<=");
   6887 		break;
   6888 	case OLET:
   6889 		cgbinaryop(cg, expr, "<");
   6890 		break;
   6891 	case OGEQ:
   6892 		cgbinaryop(cg, expr, ">=");
   6893 		break;
   6894 	case OGRT:
   6895 		cgbinaryop(cg, expr, ">");
   6896 		break;
   6897 	case ONEQ:
   6898 		cgbinaryop(cg, expr, "!=");
   6899 		break;
   6900 	case OEQU:
   6901 		cgbinaryop(cg, expr, "==");
   6902 		break;
   6903 	case OIDENT:
   6904 		/* @todo implement c version correctly */
   6905 		cgbinaryop(cg, expr, "==");
   6906 		break;
   6907 	case OLAND:
   6908 		cgbinaryop(cg, expr, "&&");
   6909 		break;
   6910 	case OLOR:
   6911 		cgbinaryop(cg, expr, "||");
   6912 		break;
   6913 	case OASS:
   6914 		cgbinaryop(cg, expr, "=");
   6915 		break;
   6916 	case OMULA:
   6917 		cgbinaryop(cg, expr, "*=");
   6918 		break;
   6919 	case ODIVA:
   6920 		cgbinaryop(cg, expr, "/=");
   6921 		break;
   6922 	case OMODA:
   6923 		cgbinaryop(cg, expr, "%=");
   6924 		break;
   6925 	case OLSHA:
   6926 		cgbinaryop(cg, expr, "<<=");
   6927 		break;
   6928 	case OARSHA:
   6929 		/* @todo implement c version correctly */
   6930 		cgbinaryop(cg, expr, ">>>=");
   6931 		break;
   6932 	case ORSHA:
   6933 		cgbinaryop(cg, expr, ">>=");
   6934 		break;
   6935 	case OANDA:
   6936 		cgbinaryop(cg, expr, "&=");
   6937 		break;
   6938 	case OADDA:
   6939 		cgbinaryop(cg, expr, "+=");
   6940 		break;
   6941 	case OSUBA:
   6942 		cgbinaryop(cg, expr, "-=");
   6943 		break;
   6944 	case OXORA:
   6945 		cgbinaryop(cg, expr, "^=");
   6946 		break;
   6947 	case OORA:
   6948 		cgbinaryop(cg, expr, "|=");
   6949 		break;
   6950 	case KBREAK:
   6951 		cgprintf(cg, "break");
   6952 		break;
   6953 	case KCONTINUE:
   6954 		cgprintf(cg, "continue");
   6955 		break;
   6956 	case KGOTO:
   6957 		cgprintf(cg, "goto %s", getstring(idents, expr->u.key));
   6958 		break;
   6959 	case KRETURN:
   6960 		cgprintf(cg, "return ");
   6961 		if (expr->rhs)
   6962 			codegen(cg, expr->rhs);
   6963 		break;
   6964 	case KWHILE:
   6965 		cgprintf(cg, "while (");
   6966 		goto joinif;
   6967 	case KFOR:
   6968 		cgprintf(cg, "for (");
   6969 		goto joinif;
   6970 	case KIF:
   6971 		cgprintf(cg, "if (");
   6972 	joinif:
   6973 		if (expr->u.payload)
   6974 			codegen(cg, expr->u.payload);
   6975 		cgprintf(cg, ") ");
   6976 		if (expr->lhs)
   6977 			cgprintclause(cg, expr->lhs);
   6978 		if (expr->rhs) {
   6979 			cgprintf(cg, " else ");
   6980 			cgprintclause(cg, expr->rhs);
   6981 		}
   6982 		cgprintf(cg, "\n");
   6983 		break;
   6984 	case AFORSTEP:
   6985 		assert(expr->lhs);
   6986 		assert(expr->rhs);
   6987 		assert(expr->u.payload);
   6988 		assert(expr->lhs->kind == ADECL || expr->lhs->kind == ADECLREF);
   6989 		codegen(cg, expr->lhs);
   6990 		cgprintf(cg, "; %s < (", getstring(idents, expr->lhs->u.declref->key));
   6991 		codegen(cg, expr->rhs);
   6992 		cgprintf(cg, "); %s += (", getstring(idents, expr->lhs->u.declref->key));
   6993 		codegen(cg, expr->u.payload);
   6994 		cgprintf(cg, ")");
   6995 		break;
   6996 	case AFOREACH:
   6997 		break;
   6998 	case KLOOP:
   6999 		cgprintf(cg, "for (;;) ");
   7000 		if (expr->lhs)
   7001 			cgprintclause(cg, expr->lhs);
   7002 		/* @todo implement else-case properly? */
   7003 		/* @note else-clause might be useless for an infinite loop */
   7004 		/*
   7005 		if (expr->rhs) {
   7006 			cgprintf(cg, " else ");
   7007 			cgprintclause(cg, expr->rhs);
   7008 		}
   7009 		*/
   7010 		cgprintf(cg, "\n");
   7011 		break;
   7012 	case ALOOPUNTIL:
   7013 		cgprintf(cg, "do ");
   7014 		if (expr->lhs)
   7015 			cgprintclause(cg, expr->lhs);
   7016 		cgprintf(cg, " while (!(");
   7017 		if (expr->u.payload)
   7018 			codegen(cg, expr->u.payload);
   7019 		cgprintf(cg, "));\n");
   7020 		/* @todo implement else-case properly */
   7021 		/*
   7022 		if (expr->rhs) {
   7023 			cgprintf(cg, " else ");
   7024 			cgprintclause(cg, expr->rhs);
   7025 		}
   7026 		*/
   7027 		break;
   7028 	case KCASE:
   7029 	case KOF:
   7030 	case KUNTIL:
   7031 		/* @todo implement c version correctly */
   7032 		break;
   7033 	case ACOMMA:
   7034 		codegen(cg, expr->lhs);
   7035 		cgprintf(cg, ", ");
   7036 		++cg->commacount;
   7037 		codegen(cg, expr->rhs);
   7038 		--cg->commacount;
   7039 		break;
   7040 	case KUNION:
   7041 		cgprintf(cg, "union ");
   7042 		goto joinstruct;
   7043 	case KSTRUCT:
   7044 		cgprintf(cg, "struct ");
   7045 
   7046 	joinstruct:
   7047 		assert(expr->type);
   7048 		if (expr->type->module)
   7049 			cgdeclname(cg, expr->type->module);
   7050 
   7051 		cgprintf(cg, " {\n");
   7052 		++cg->indent;
   7053 		if (expr->rhs)
   7054 			codegen(cg, expr->rhs);
   7055 		--cg->indent;
   7056 		cgindent(cg);
   7057 		cgprintf(cg, "}");
   7058 		break;
   7059 	case INVALID:
   7060 	case LINEDELIM:
   7061 	case SEMIDELIM:
   7062 	case COMMADELIM:
   7063 	case COLONDELIM:
   7064 	case LCURLDELIM:
   7065 	case LSQRDELIM:
   7066 	case LPARDELIM:
   7067 	case RCURLDELIM:
   7068 	case RSQRDELIM:
   7069 	case RPARDELIM:
   7070 	case ANNOT:
   7071 	case KVOID:
   7072 	case KBOOL:
   7073 	case KU8:
   7074 	case KS8:
   7075 	case KU16:
   7076 	case KS16:
   7077 	case KU32:
   7078 	case KS32:
   7079 	case KU64:
   7080 	case KS64:
   7081 	case KF32:
   7082 	case KF64:
   7083 	case KUCHAR:
   7084 	case KCHAR:
   7085 	case KUSHORT:
   7086 	case KSHORT:
   7087 	case KUINT:
   7088 	case KINT:
   7089 	case KULONG:
   7090 	case KLONG:
   7091 	case KULLONG:
   7092 	case KLLONG:
   7093 	case KFLOAT:
   7094 	case KDOUBLE:
   7095 	case KLDOUBLE:
   7096 	case KUSIZE:
   7097 	case KSSIZE:
   7098 	case KUSE:
   7099 	case KNOT:
   7100 	case KAND:
   7101 	case KOR:
   7102 	case KIS:
   7103 	case KBITCAST:
   7104 	case KEXTERN:
   7105 	case KINTERN:
   7106 	case KSTATIC:
   7107 	case KCONST:
   7108 	case KVAR:
   7109 	case KELSE:
   7110 	case MAXKINDS:
   7111 	case ENDOFFILE:
   7112 		cgprintf(cg, "<not implemented: '%s' ", nodestrings[expr->kind]);
   7113 		if (expr->lhs)
   7114 			codegen(cg, expr->lhs);
   7115 		cgprintf(cg, " ");
   7116 		if (expr->rhs)
   7117 			codegen(cg, expr->rhs);
   7118 		cgprintf(cg, ">");
   7119 		break;
   7120 	}
   7121 }
   7122 
   7123 
   7124 
   7125 // }}}
   7126 
   7127 // @section print ast {{{
   7128 
   7129 static void
   7130 promptenvpath(Env* currenv)
   7131 {
   7132 	const char *envstring = "environment";
   7133 
   7134 	if (currenv && currenv->kind != STOPLEVEL) {
   7135 		promptenvpath(currenv->below);
   7136 
   7137 		switch (currenv->kind) {
   7138 		case SFUNCTION:
   7139 		case SPARAMLIST:
   7140 			envstring = "function";
   7141 			break;
   7142 		case SSTRUCT:
   7143 			envstring = "struct";
   7144 			break;
   7145 		case SUNION:
   7146 			envstring = "union";
   7147 			break;
   7148 		case SSCOPE:
   7149 			envstring = "scope";
   7150 			break;
   7151 		case SIF:
   7152 			envstring = "if";
   7153 			break;
   7154 		case SELSE:
   7155 			envstring = "else";
   7156 			break;
   7157 		case SDO:
   7158 			envstring = "do";
   7159 			break;
   7160 		case SLOOP:
   7161 			envstring = "loop";
   7162 			break;
   7163 		case SWHILE:
   7164 			envstring = "while";
   7165 			break;
   7166 		default:
   7167 			break;
   7168 		}
   7169 
   7170 		if (currenv->envdecl) {
   7171 			int key = currenv->envdecl->key;
   7172 			envstring = getstring(idents, key);
   7173 		}
   7174 
   7175 		fprintf(stdout, "# scope: %s/", envstring);
   7176 	}
   7177 }
   7178 
   7179 static void
   7180 tryprompt(Source *source, const char ch)
   7181 {
   7182 	if (source->handlereplprompt) {
   7183 		Env *currenv = source->currenv;
   7184 
   7185 		if (ch == '.' && currenv && currenv->kind != STOPLEVEL) {
   7186 			fputs("\x1b[1;30m", stdout);
   7187 			promptenvpath(currenv);
   7188 			fprintf(stdout, "\n\x1b[35m%c \x1b[0m", ch);
   7189 		} else {
   7190 			fprintf(stdout, "\x1b[35m%c \x1b[0m", ch);
   7191 		}
   7192 
   7193 	} else if (source->filein == stdin) {
   7194 		source->handlereplprompt = true;
   7195 	}
   7196 }
   7197 
   7198 typedef
   7199 enum Highlight {
   7200 	HLNONE = 0,
   7201 	HLDELIM = 1,
   7202 	HLUNKNOWN = 2,
   7203 	HLKEYWORD = 3,
   7204 	HLNUMBER = 4,
   7205 	HLSTRING = 5,
   7206 	HLTYPE = 6,
   7207 	HLFUNCTION = 7,
   7208 	HLPARAM = 8,
   7209 	#if 0
   7210 	HLFUNCTIONDECL = 9,
   7211 	HLPARAMDECL = 10,
   7212 	HLDECL = 11,
   7213 	#endif
   7214 	HLSPECIAL = 12,
   7215 	HLINFO = 13,
   7216 	HLPROMPT = 14
   7217 } Highlight;
   7218 
   7219 #define HLFUNCTIONDECL HLFUNCTION
   7220 #define HLPARAMDECL HLPARAM
   7221 #define HLDECL HLIDENT
   7222 
   7223 #define HLOP HLDELIM
   7224 #define HLCHAR HLSTRING
   7225 #define HLIDENT HLNONE
   7226 
   7227 Highlight lasthighlight;
   7228 
   7229 static int
   7230 highlight(FILE *out, Highlight kind)
   7231 {
   7232 	int n = 0;
   7233 
   7234 	if (out != stdout)
   7235 		return 0;
   7236 
   7237 	if (lasthighlight == kind)
   7238 		return 0;
   7239 
   7240 	if (kind == HLNONE)
   7241 		return lasthighlight = kind, fprintf(out, "\x1b[0m");
   7242 
   7243 	if (lasthighlight == HLDELIM || kind == HLDELIM ||
   7244 	    lasthighlight == HLFUNCTION || kind == HLFUNCTION ||
   7245 	    lasthighlight == HLPARAM || kind == HLPARAM ||
   7246 	    #if 0
   7247 	    lasthighlight == HLFUNCTIONDECL || kind == HLFUNCTIONDECL ||
   7248 	    lasthighlight == HLPARAMDECL || kind == HLPARAMDECL ||
   7249 	    lasthighlight == HLDECL || kind == HLDECL ||
   7250 	    #endif
   7251 	    lasthighlight == HLSPECIAL ||
   7252 	    lasthighlight == HLUNKNOWN || kind == HLUNKNOWN)
   7253 		n += fprintf(out, "\x1b[0m");
   7254 
   7255 	switch (kind) {
   7256 	case HLDELIM:
   7257 		n += fprintf(out, "\x1b[2m");
   7258 		break;
   7259 
   7260 	case HLUNKNOWN:
   7261 		n += fprintf(out, "\x1b[41;30m");
   7262 		break;
   7263 
   7264 	case HLKEYWORD:
   7265 		n += fprintf(out, "\x1b[35m");
   7266 		break;
   7267 
   7268 	case HLNUMBER:
   7269 		n += fprintf(out, "\x1b[36m");
   7270 		break;
   7271 
   7272 	case HLSTRING:
   7273 		n += fprintf(out, "\x1b[31m");
   7274 		break;
   7275 
   7276 	case HLTYPE:
   7277 		n += fprintf(out, "\x1b[34m");
   7278 		break;
   7279 
   7280 	case HLFUNCTION:
   7281 		n += fprintf(out, "\x1b[1;3m");
   7282 		break;
   7283 
   7284 	case HLPARAM:
   7285 		n += fprintf(out, "\x1b[3m");
   7286 		break;
   7287 
   7288 	#if 0
   7289 	case HLFUNCTIONDECL:
   7290 		n += fprintf(out, "\x1b[1;4;3m");
   7291 		break;
   7292 
   7293 	case HLPARAMDECL:
   7294 		n += fprintf(out, "\x1b[4;3m");
   7295 		break;
   7296 
   7297 	case HLDECL:
   7298 		n += fprintf(out, "\x1b[4m");
   7299 		break;
   7300 	#endif
   7301 
   7302 	case HLSPECIAL:
   7303 		n += fprintf(out, "\x1b[3;36m");
   7304 		break;
   7305 
   7306 	case HLINFO:
   7307 		n += fprintf(out, "\x1b[33m");
   7308 		break;
   7309 
   7310 	case HLPROMPT:
   7311 		n += fprintf(out, "\x1b[35m");
   7312 		break;
   7313 	default:
   7314 		break;
   7315 	}
   7316 
   7317 	lasthighlight = kind;
   7318 	return n;
   7319 }
   7320 
   7321 static int
   7322 printexpr(FILE *out, Node *expr, int indent);
   7323 
   7324 static int
   7325 printtypetail(FILE *out, Type *type, int indent)
   7326 {
   7327 	int n = 0;
   7328 
   7329 	if (!type)
   7330 		return 0;
   7331 
   7332 	if (type->kind == TFUNCTION) {
   7333 		n += printtypetail(out, type->u.rtarget, indent);
   7334 		n += fprintf(out, " function(");
   7335 		if (type->target)
   7336 			n += printtypetail(out, type->target, indent);
   7337 		n += fprintf(out, ")");
   7338 		return n;
   7339 	}
   7340 
   7341 	if (type->kind != TTUPLE && type->target &&
   7342 	    type->target->kind == TTUPLE)
   7343 	{
   7344 		n += fprintf(out, "(");
   7345 		n += printtypetail(out, type->target, indent);
   7346 		n += fprintf(out, ")");
   7347 	} else {
   7348 		n += printtypetail(out, type->target, indent);
   7349 	}
   7350 
   7351 	if (type->module) {
   7352 		n += fprintf(out, "%s", getstring(idents, type->module->key));
   7353 		return n;
   7354 	}
   7355 
   7356 	switch (type->kind) {
   7357 	case TARRAY:
   7358 		n += fprintf(out, "[");
   7359 
   7360 		/* @note the value may be always set in the future */
   7361 		if (type->u.val)
   7362 			n += printexpr(out, type->u.val, indent);
   7363 
   7364 		n += fprintf(out, "]");
   7365 		break;
   7366 
   7367 	case TTUPLE:
   7368 		n += fprintf(out, ", ");
   7369 		if (type->u.rtarget && type->u.rtarget->kind == TTUPLE) {
   7370 			n += fprintf(out, "(");
   7371 			n += printtypetail(out, type->u.rtarget, indent);
   7372 			n += fprintf(out, ")");
   7373 		} else {
   7374 			n += printtypetail(out, type->u.rtarget, indent);
   7375 		}
   7376 
   7377 		break;
   7378 
   7379 	#define typecase(type, str) \
   7380 		case type: n += fprintf(out, str); break
   7381 
   7382 	typecase(TERRTYPE,   "<error-type>");
   7383 	typecase(TUNDEFINED, "<undefined-type>");
   7384 	typecase(TPTR,       "*");
   7385 	typecase(TVOID,      "void" ); typecase(TBOOL,   "bool"  );
   7386 	typecase(TINFER,     "infer"); typecase(TUINFER, "uinfer");
   7387 	typecase(TS8,        "char" ); typecase(TU8,     "uchar" );
   7388 	typecase(TS16,       "s16"  ); typecase(TU16,    "u16"   );
   7389 	typecase(TS32,       "int"  ); typecase(TU32,    "uint"  );
   7390 	typecase(TS64,       "s64"  ); typecase(TU64,    "u64"   );
   7391 	typecase(TF32,       "float"); typecase(TF64,    "double");
   7392 
   7393 	#undef typecase
   7394 	default:;
   7395 	}
   7396 
   7397 	return n;
   7398 }
   7399 
   7400 static int
   7401 printtype(FILE *out, Type *type, int indent)
   7402 {
   7403 	if (type && type->kind == TTUPLE) {
   7404 		int n = 0;
   7405 
   7406 		n += fprintf(out, "(");
   7407 		n += printtypetail(out, type, indent);
   7408 
   7409 		return n + fprintf(out, ")");
   7410 	}
   7411 
   7412 	return printtypetail(out, type, indent);
   7413 }
   7414 
   7415 static int
   7416 printtypesuffix(FILE *out, Type *type)
   7417 {
   7418 	int n = 0;
   7419 
   7420 	if (!type)
   7421 		return 0;
   7422 
   7423 	switch (type->kind) {
   7424 	#define typecase(type, str) \
   7425 		case type: n += fprintf(out, str); break
   7426 
   7427 	typecase(TINFER,     "i"    ); typecase(TUINFER, "u"     );
   7428 	typecase(TS8,        "s8"   ); typecase(TU8,     "u8"    );
   7429 	typecase(TS16,       "s16"  ); typecase(TU16,    "u16"   );
   7430 	typecase(TS32,       "s32"  ); typecase(TU32,    "u32"   );
   7431 	typecase(TS64,       "s64"  ); typecase(TU64,    "u64"   );
   7432 	typecase(TF32,       "f32"  ); typecase(TF64,    "f64"   );
   7433 
   7434 	#undef typecase
   7435 	default:;
   7436 	}
   7437 
   7438 	return n;
   7439 }
   7440 
   7441 static bool
   7442 isclauseorempty(Node *expr)
   7443 {
   7444 	Kind kind;
   7445 
   7446 	while (expr && (expr->kind == ASCOPE || expr->kind == ASTMT))
   7447 		expr = expr->lhs;
   7448 
   7449 	if (!expr)
   7450 		return true;
   7451 
   7452 	kind = expr->kind;
   7453 	return kind == KDO   || kind == KIF     || kind == KFOR   ||
   7454 	       kind == KGOTO || kind == KRETURN || kind == KBREAK ||
   7455 	       kind == KCONTINUE;
   7456 }
   7457 
   7458 static int
   7459 printclause(FILE *out, Node *expr, int indent)
   7460 {
   7461 	int n = 0;
   7462 
   7463 	if (!expr)
   7464 		return 0;
   7465 
   7466 	if (isclauseorempty(expr)) {
   7467 		n += fprintf(out, " ");
   7468 		n += printexpr(out, expr, indent);
   7469 	} else {
   7470 		n += fprintf(out, "\n");
   7471 		n += printexpr(out, expr, indent + 1);
   7472 	}
   7473 
   7474 	return n;
   7475 }
   7476 
   7477 static int
   7478 printstring(FILE *out, Node *string)
   7479 {
   7480 	const char *str = getstring(strings, string->u.key);
   7481 	int len = getlength(strings, string->u.key);
   7482 	int i, n = fprintf(out, "\"");
   7483 
   7484 	for (i = 0; i < len; ++i) {
   7485 		switch (str[i]) {
   7486 		case '\\':
   7487 			n += fprintf(out, "\\\\");
   7488 			break;
   7489 
   7490 		case '\n':
   7491 			n += fprintf(out, "\\n");
   7492 			break;
   7493 
   7494 		case '\r':
   7495 			n += fprintf(out, "\\r");
   7496 			break;
   7497 
   7498 		case '\t':
   7499 			n += fprintf(out, "\\t");
   7500 			break;
   7501 
   7502 		case '\"':
   7503 			n += fprintf(out, "\\\"");
   7504 			break;
   7505 
   7506 		case '\'':
   7507 			n += fprintf(out, "\\\'");
   7508 			break;
   7509 
   7510 		case 0:
   7511 			n += fprintf(out, "\\0");
   7512 			break;
   7513 
   7514 		default:
   7515 			putc(str[i], out);
   7516 			++n;
   7517 		}
   7518 	}
   7519 
   7520 	return n + fprintf(out, "\"");
   7521 }
   7522 
   7523 static int
   7524 printoperant(FILE *out, Node *expr, int opprec, bool braceequalprec, int indent)
   7525 {
   7526 	int prec, n = 0;
   7527 
   7528 	if (!expr)
   7529 		return 0;
   7530 
   7531 	prec = getprec(expr->kind);
   7532 	if (!isatomnode(expr->kind) && (!getnumops(expr->kind) ||
   7533 	     prec < opprec ||
   7534 	    (braceequalprec && prec == opprec))) {
   7535 		n += highlight(out, HLDELIM);
   7536 
   7537 		n += fprintf(out, "(");
   7538 		n += highlight(out, HLNONE);
   7539 		n += printexpr(out, expr, indent);
   7540 		n += highlight(out, HLDELIM);
   7541 		n += fprintf(out, ")");
   7542 
   7543 		n += highlight(out, HLNONE);
   7544 	} else {
   7545 		n += printexpr(out, expr, indent);
   7546 	}
   7547 
   7548 	return n;
   7549 }
   7550 
   7551 static int
   7552 printsubexpr(FILE *out, Node *expr, bool islhs, int indent)
   7553 {
   7554 	int n = 0;
   7555 
   7556 	if (!expr)
   7557 		return 0;
   7558 
   7559 	if ((islhs && expr->kind == ACOMMA) || expr->kind == ADECL)
   7560 		n += printexpr(out, expr, indent);
   7561 	else
   7562 		n += printoperant(out, expr, PSTART, !islhs, indent);
   7563 
   7564 	return n;
   7565 }
   7566 
   7567 static int
   7568 printdeclmodule(FILE *out, Decl *module)
   7569 {
   7570 	int n = 0;
   7571 
   7572 	if (module->module)
   7573 		printdeclmodule(out, module->module);
   7574 
   7575 	if (module->kind == DTYPE) {
   7576 		n += highlight(out, HLTYPE);
   7577 		fprintf(out, "%s", getstring(idents, module->key));
   7578 		n += highlight(out, HLDELIM);
   7579 	} else {
   7580 		n += highlight(out, HLDELIM);
   7581 		fprintf(out, "%s", getstring(idents, module->key));
   7582 	}
   7583 	n += fprintf(out, ".");
   7584 
   7585 	return n;
   7586 }
   7587 
   7588 static int
   7589 printdeclname(FILE *out, Decl *decl, bool isdecl)
   7590 {
   7591 	int n = 0;
   7592 
   7593 	if (decl->module)
   7594 		printdeclmodule(out, decl->module);
   7595 
   7596 	if (isdecl) {
   7597 		n += highlight(out,
   7598 			decl->kind == DFUNCTION ? HLFUNCTIONDECL :
   7599 			decl->kind == DPARAM ? (
   7600 				decl->flags & MSPECIAL ? HLSPECIAL : HLPARAMDECL
   7601 			) : HLDECL);
   7602 	} else {
   7603 		n += highlight(out, decl->kind == DFUNCTION ?
   7604 			HLFUNCTION : decl->kind == DPARAM ? (
   7605 				decl->flags & MSPECIAL ? HLSPECIAL : HLPARAM
   7606 			) : HLIDENT);
   7607 	}
   7608 	n += fprintf(out, "%s", getstring(idents, decl->key));
   7609 
   7610 	return n;
   7611 }
   7612 
   7613 static int
   7614 printdeclaration(FILE *out, Decl *decl, int indent)
   7615 {
   7616 	int n = 0;
   7617 
   7618 	assert(decl);
   7619 
   7620 	n += highlight(out, HLTYPE);
   7621 	if (decl->kind == DFUNCTION) {
   7622 		n += printtype(out, decl->type->u.rtarget, indent);
   7623 	} else {
   7624 		n += printtype(out, decl->type, indent);
   7625 	}
   7626 
   7627 	n += fprintf(out, " ");
   7628 	printdeclname(out, decl, true);
   7629 
   7630 	if (decl->kind == DFUNCTION) {
   7631 		Decl *param, *head = NULL;
   7632 
   7633 		n += highlight(out, HLDELIM);
   7634 		n += fprintf(out, "(");
   7635 
   7636 		if (decl->contentenv) {
   7637 			head = decl->contentenv->head;
   7638 		}
   7639 
   7640 		for (param = head; param; param = param->next) {
   7641 			if (param->kind != DPARAM)
   7642 				break;
   7643 
   7644 			if (param != head) {
   7645 				n += highlight(out, HLDELIM);
   7646 				n += fprintf(out, ", ");
   7647 			}
   7648 
   7649 			n += printdeclaration(out, param, indent + 1);
   7650 		}
   7651 
   7652 		n += highlight(out, HLDELIM);
   7653 		n += fprintf(out, ")");
   7654 
   7655 		if (decl->u.content) {
   7656 			n += fprintf(out, "\n");
   7657 			n += printexpr(out, decl->u.content, indent + 1);
   7658 		}
   7659 	} else if (decl->u.content) {
   7660 		n += highlight(out, HLDELIM);
   7661 		n += fprintf(out, " = ");
   7662 		n += printoperant(out, decl->u.content, PASSIGN, false, indent);
   7663 	}
   7664 
   7665 	return n;
   7666 }
   7667 
   7668 static int
   7669 printexpr(FILE *out, Node *expr, int indent)
   7670 {
   7671 	int n = 0;
   7672 
   7673 	if (expr->kind == 0) {
   7674 		n += highlight(out, HLKEYWORD);
   7675 		n += fprintf(out, "_");
   7676 		return 0;
   7677 	}
   7678 
   7679 	if (getnumops(expr->kind) == 2) {
   7680 		n += printoperant(out, expr->lhs,
   7681 			getprec(expr->kind),
   7682 			israssoc(expr->kind),
   7683 			indent);
   7684 
   7685 		n += highlight(out, HLDELIM);
   7686 		n += fprintf(out, " %s ", nodestrings[expr->kind]);
   7687 
   7688 		n += printoperant(out, expr->rhs,
   7689 			getprec(expr->kind),
   7690 			!israssoc(expr->kind),
   7691 			indent);
   7692 		goto finish;
   7693 	}
   7694 	
   7695 	if (getnumops(expr->kind) == 1) {
   7696 		if (getprec(expr->kind) == PUNSUF) {
   7697 			printoperant(out, expr->lhs, PUNSUF, false, indent);
   7698 
   7699 			switch (expr->kind) {
   7700 			case OARRAY:
   7701 			case OCALL:
   7702 				n += highlight(out, HLDELIM);
   7703 				n += fprintf(out, "%c", nodestrings[expr->kind][0]);
   7704 
   7705 				if (expr->rhs)
   7706 					n += printexpr(out, expr->rhs, indent);
   7707 
   7708 				n += highlight(out, HLDELIM);
   7709 				n += fprintf(out, "%c", nodestrings[expr->kind][1]);
   7710 				break;
   7711 
   7712 			case ODISP:
   7713 				n += highlight(out, HLDELIM);
   7714 				n += fprintf(out, ".");
   7715 				if (expr->rhs && expr->rhs->kind == IDENT) {
   7716 					n += highlight(out, HLIDENT);
   7717 					n += fprintf(out, "%s",
   7718 						getstring(idents, expr->rhs->u.key));
   7719 				} else {
   7720 					/* @note this might be unnecessary */
   7721 					n += printexpr(out, expr->rhs, indent);
   7722 				}
   7723 				break;
   7724 
   7725 			default:
   7726 				n += highlight(out, HLDELIM);
   7727 				n += fprintf(out, "%s", nodestrings[expr->kind]);
   7728 			}
   7729 
   7730 		} else {
   7731 			switch (expr->kind) {
   7732 			case OCAST:
   7733 				n += highlight(out, HLDELIM);
   7734 				putc('(', out), ++n;
   7735 				n += highlight(out, HLTYPE);
   7736 				n += printtype(out, expr->type, indent);
   7737 				n += highlight(out, HLDELIM);
   7738 				putc(')', out), ++n;
   7739 				break;
   7740 
   7741 			default:
   7742 				n += highlight(out, HLDELIM);
   7743 				n += fprintf(out, "%s", nodestrings[expr->kind]);
   7744 
   7745 				if (getprec(expr->lhs->kind) == PUNARY &&
   7746 					expr->kind != ODEREF &&
   7747 					expr->kind != OADDR)
   7748 				{
   7749 					putc(' ', out), ++n;
   7750 				}
   7751 			}
   7752 
   7753 			n += printoperant(out, expr->lhs, PUNARY, false, indent);
   7754 		}
   7755 
   7756 		goto finish;
   7757 	}
   7758 	
   7759 	switch (expr->kind) {
   7760 	case IDENT:
   7761 		n += highlight(out, HLUNKNOWN);
   7762 		n += fprintf(out, "%s?", getstring(idents, expr->u.key));
   7763 		n += highlight(out, HLNONE);
   7764 		break;
   7765 
   7766 	case NUMBER:
   7767 		n += highlight(out, HLNUMBER);
   7768 
   7769 		switch (expr->type->kind) {
   7770 		case TF32: case TF64:
   7771 		/* case TLDOUBLE: */
   7772 			n += fprintf(out, "%f", expr->u.d);
   7773 			n += printtypesuffix(out, expr->type);
   7774 			break;
   7775 
   7776 		case TINFER:
   7777 		case TS8:  case TS16: case TS32: case TS64:
   7778 			n += fprintf(out, "%lli", expr->u.s);
   7779 			n += printtypesuffix(out, expr->type);
   7780 			break;
   7781 
   7782 		case TUINFER:
   7783 		case TU8:  case TU16: case TU32: case TU64:
   7784 			n += fprintf(out, "%llu", expr->u.s);
   7785 			n += printtypesuffix(out, expr->type);
   7786 			break;
   7787 
   7788 		case TBOOL:
   7789 			if (expr->u.u == 0)
   7790 				n += fprintf(out, "false");
   7791 			else if (expr->u.u == 1)
   7792 				n += fprintf(out, "true");
   7793 			else
   7794 				n += fprintf(out, "0x%016llx", expr->u.u);
   7795 
   7796 			break;
   7797 
   7798 		case TPTR:
   7799 			if (expr->u.u == 0)
   7800 				n += fprintf(out, "null");
   7801 			else
   7802 				n += fprintf(out, "0x%016llx", expr->u.u);
   7803 			break;
   7804 
   7805 		case TVOID:
   7806 		default:
   7807 			n += fprintf(out, "---");
   7808 			break;
   7809 
   7810 		}
   7811 
   7812 		break;
   7813 
   7814 	case CHAR:
   7815 		/* @todo print chars correctly */
   7816 		n += highlight(out, HLCHAR);
   7817 		n += fprintf(out, "'%c'", (uchar) expr->u.u);
   7818 		break;
   7819 
   7820 	case STRING:
   7821 		n += highlight(out, HLSTRING);
   7822 		n += printstring(out, expr);
   7823 		break;
   7824 
   7825 	case TYPE:
   7826 		/* @note might be unnecessary (only used for ACOMPOUND) */
   7827 		n += highlight(out, HLTYPE);
   7828 		n += printtype(out, expr->type, indent);
   7829 		break;
   7830 
   7831 	case ADECLREF:
   7832 		printdeclname(out, expr->u.declref, false);
   7833 		break;
   7834 	
   7835 	case ADECL:
   7836 		n += printdeclaration(out, expr->u.declref, indent);
   7837 		break;
   7838 
   7839 	case ACOMMA:
   7840 		n += printsubexpr(out, expr->lhs, true, indent);
   7841 		n += highlight(out, HLDELIM);
   7842 		n += printf(", ");
   7843 		n += printsubexpr(out, expr->rhs, false, indent);
   7844 		break;
   7845 
   7846 	case KSIZEOF:
   7847 	case KALIGNOF:
   7848 	case KLENGTHOF:
   7849 		n += highlight(out, HLKEYWORD);
   7850 		n += fprintf(out, "%s", nodestrings[expr->kind]);
   7851 		n += highlight(out, HLDELIM);
   7852 
   7853 		n += fprintf(out, "(");
   7854 		n += printexpr(out, expr->lhs, indent);
   7855 		n += highlight(out, HLDELIM);
   7856 		n += fprintf(out, ")");
   7857 		break;
   7858 
   7859 	case KBITCAST:
   7860 		n += highlight(out, HLKEYWORD);
   7861 		n += fprintf(out, "bitcast");
   7862 		n += highlight(out, HLDELIM);
   7863 		n += fprintf(out, "(");
   7864 
   7865 		n += highlight(out, HLTYPE);
   7866 		n += printtype(out, expr->rhs->type, indent);
   7867 		n += highlight(out, HLDELIM);
   7868 
   7869 		n += fprintf(out, ") (");
   7870 		n += printexpr(out, expr->lhs, indent);
   7871 		n += highlight(out, HLDELIM);
   7872 		n += fprintf(out, ")");
   7873 		break;
   7874 
   7875 	case KRETURN:
   7876 		n += highlight(out, HLKEYWORD);
   7877 		if (expr->rhs) {
   7878 			n += fprintf(out, "return ");
   7879 			n += printexpr(out, expr->rhs, indent);
   7880 		} else {
   7881 			n += fprintf(out, "return");
   7882 		}
   7883 		break;
   7884 
   7885 	case KBREAK:
   7886 		n += highlight(out, HLKEYWORD);
   7887 		n += fprintf(out, "break");
   7888 		break;
   7889 
   7890 	case KCONTINUE:
   7891 		n += highlight(out, HLKEYWORD);
   7892 		n += fprintf(out, "continue");
   7893 		break;
   7894 	case KWHILE:
   7895 		n += highlight(out, HLKEYWORD);
   7896 		n += fprintf(out, "while ");
   7897 		goto joinifbody;
   7898 
   7899 	case KFOR:
   7900 		n += highlight(out, HLKEYWORD);
   7901 		n += fprintf(out, "for ");
   7902 		goto joinifbody;
   7903 	
   7904 	case AFORSTEP:
   7905 		n += printexpr(out, expr->lhs, indent);
   7906 		n += highlight(out, HLKEYWORD);
   7907 		n += fprintf(out, " to ");
   7908 		n += printexpr(out, expr->rhs, indent);
   7909 
   7910 		assert(expr->u.payload);
   7911 		if (expr->u.payload->kind == NUMBER && false) {
   7912 			if (isfloattype(expr->u.payload->type)
   7913 			&&  expr->u.payload->u.d == 1.0)
   7914 				break;
   7915 			if (isinttype(expr->u.payload->type)
   7916 			&&  expr->u.payload->u.u == 1)
   7917 				break;
   7918 		}
   7919 		n += highlight(out, HLKEYWORD);
   7920 		n += fprintf(out, " step ");
   7921 		n += printexpr(out, expr->u.payload, indent);
   7922 		break;
   7923 
   7924 	case KIF:
   7925 		n += highlight(out, HLKEYWORD);
   7926 		n += fprintf(out, "if ");
   7927 		/* FALLTHROUGH */
   7928 	joinifbody:
   7929 		n += printexpr(out, expr->u.payload, indent);
   7930 		n += printclause(out, expr->lhs, indent);
   7931 
   7932 		if (expr->rhs) {
   7933 			int i;
   7934 
   7935 			n += fprintf(out, "\n");
   7936 
   7937 			for (i = 0; i < indent; ++i)
   7938 				n += fprintf(out, "\t");
   7939 
   7940 			n += highlight(out, HLKEYWORD);
   7941 			n += fprintf(out, "else");
   7942 			n += printclause(out, expr->rhs, indent);
   7943 		}
   7944 		break;
   7945 
   7946 	case KLOOP:
   7947 	case ALOOPUNTIL:
   7948 		n += highlight(out, HLKEYWORD);
   7949 		n += fprintf(out, "loop");
   7950 		n += printclause(out, expr->lhs, indent);
   7951 		if (expr->kind == KLOOP)
   7952 			break;
   7953 
   7954 		do {
   7955 			int i;
   7956 			n += fprintf(out, "\n");
   7957 
   7958 			for (i = 0; i < indent; ++i)
   7959 				n += fprintf(out, "\t");
   7960 
   7961 		} while (0);
   7962 
   7963 		n += highlight(out, HLKEYWORD);
   7964 		n += fprintf(out, "until ");
   7965 		n += printexpr(out, expr->u.payload, indent);
   7966 
   7967 		if (expr->rhs) {
   7968 			n += highlight(out, HLKEYWORD);
   7969 			n += fprintf(out, " else");
   7970 			n += printclause(out, expr->rhs, indent);
   7971 		}
   7972 		break;
   7973 
   7974 
   7975 	case KDO:
   7976 		n += highlight(out, HLKEYWORD);
   7977 		n += fprintf(out, "do");
   7978 		n += printclause(out, expr->lhs, indent);
   7979 		break;
   7980 
   7981 	case KUNION:
   7982 	case KSTRUCT:
   7983 		n += highlight(out, HLKEYWORD);
   7984 
   7985 		n += fprintf(out,
   7986 			expr->kind == KSTRUCT ? "struct" : "union");
   7987 
   7988 		if (expr->lhs && expr->lhs->kind == IDENT) {
   7989 			n += highlight(out, HLTYPE);
   7990 			n += fprintf(out, " %s",
   7991 				getstring(idents, expr->lhs->u.key));
   7992 		}
   7993 
   7994 		if (expr->rhs)
   7995 			n += printclause(out, expr->rhs, indent);
   7996 
   7997 		break;
   7998 
   7999 	case ASTMT:
   8000 	advancestmt:
   8001 		do {
   8002 			int i;
   8003 
   8004 			for (i = 0; i < indent; ++i)
   8005 				n += fprintf(out, "\t");
   8006 		} while (0);
   8007 
   8008 		n += printexpr(out, expr->lhs, indent);
   8009 
   8010 		if (expr->rhs) {
   8011 			assert(expr->rhs->kind == ASTMT);
   8012 			n += fprintf(out, "\n");
   8013 			expr = expr->rhs;
   8014 			goto advancestmt;
   8015 		}
   8016 
   8017 		break;
   8018 
   8019 	case ASCOPE:
   8020 		/* @todo improve this piece of code */
   8021 		if (expr->lhs                      &&
   8022 			expr->lhs->kind == ASTMT       &&
   8023 			expr->u.env                    &&
   8024 			!isrecordenv(expr->u.env))
   8025 		{
   8026 			Node *stmt = expr->lhs;
   8027 
   8028 			if (!stmt->rhs && isclauseorempty(stmt)) {
   8029 				n += printexpr(out, stmt->lhs, indent);
   8030 				break;
   8031 			}
   8032 		}
   8033 		n += printexpr(out, expr->lhs, indent);
   8034 		// n += fprintf(out, "\n"); /* blank line */
   8035 		break;
   8036 	
   8037 	case AENV:
   8038 		n += printexpr(out, expr->lhs, indent);
   8039 		break;
   8040 
   8041 	case ACONV:
   8042 		n += highlight(out, HLNUMBER);
   8043 		n += fprintf(out, "conv(");
   8044 
   8045 		n += highlight(out, HLTYPE);
   8046 		n += printtype(out, expr->type, indent);
   8047 		n += highlight(out, HLDELIM);
   8048 
   8049 		n += fprintf(out, ") ");
   8050 		n += printoperant(out, expr->lhs, PUNARY, false, indent);
   8051 		break;
   8052 
   8053 	case AADDR:
   8054 		n += highlight(out, HLDELIM);
   8055 		n += fputs("&{", out);
   8056 		n += printoperant(out, expr->lhs, PUNARY, false, indent);
   8057 		n += highlight(out, HLDELIM);
   8058 		n += fputs("}", out);
   8059 		break;
   8060 
   8061 	case ADEREF:
   8062 		n += highlight(out, HLDELIM);
   8063 		n += fputs("*{", out);
   8064 		n += printoperant(out, expr->lhs, PUNARY, false, indent);
   8065 		n += highlight(out, HLDELIM);
   8066 		n += fputs("}", out);
   8067 		break;
   8068 
   8069 	case ACOMPOUND:
   8070 		n += highlight(out, HLTYPE);
   8071 		n += printtype(out, expr->type, indent);
   8072 		n += highlight(out, HLDELIM);
   8073 		n += fputs("{", out);
   8074 		n += printexpr(out, expr->rhs, indent);
   8075 		n += highlight(out, HLDELIM);
   8076 		n += fputs("}", out);
   8077 		break;
   8078 
   8079 	case AFIELDINIT:
   8080 		if (expr->lhs) {
   8081 			n += highlight(out, HLDELIM);
   8082 			n += fprintf(out, "%s: ", getstring(idents, expr->u.key));
   8083 		}
   8084 		n += printexpr(out, expr->rhs, indent);
   8085 		break;
   8086 
   8087 	case ASELFDISP:
   8088 		n += printexpr(out, expr->lhs, indent);
   8089 		n += highlight(out, HLNONE);
   8090 		/* @todo use printexpr when typechecked */
   8091 		n += fprintf(out, ":%s", getstring(idents, expr->rhs->u.key));
   8092 		break;
   8093 
   8094 	default:
   8095 		n += highlight(out, HLINFO);
   8096 		n += fprintf(out, "node(%u)", expr->kind);
   8097 
   8098 		if (expr->lhs) {
   8099 			n += fprintf(out, " -> ");
   8100 			n += printsubexpr(out, expr->lhs, true, indent);
   8101 		}
   8102 		if (expr->rhs) {
   8103 			n += highlight(out, HLINFO);
   8104 			n += fprintf(out, " => ");
   8105 			n += printsubexpr(out, expr->rhs, false, indent);
   8106 		}
   8107 
   8108 		break;
   8109 	}
   8110 
   8111 finish:
   8112 	#if 0
   8113 	if (expr->kind == ASTMT && expr->next) {
   8114 		n += fprintf(out, "\n");
   8115 	} else if (expr->next) {
   8116 		n += highlight(out, HLDELIM);
   8117 		n += fprintf(out, ", ");
   8118 	}
   8119 	#endif
   8120 
   8121 	return n;
   8122 }
   8123 
   8124 
   8125 
   8126 // }}}
   8127 
   8128 // @section toplevel bundle & use {{{
   8129 
   8130 #if 0
   8131 typedef struct String String;
   8132 struct String {
   8133 	char *string;
   8134 	int length;
   8135 };
   8136 
   8137 static String
   8138 makestring(char *string)
   8139 {
   8140 	String result;
   8141 
   8142 	result.string = string;
   8143 	result.length = strlen(string);
   8144 
   8145 	return result;
   8146 }
   8147 
   8148 static bool
   8149 endswithcase(String name, String ending)
   8150 {
   8151 	const int delta = name.length - ending.length;
   8152 	int i;
   8153 
   8154 	if (name.length < ending.length)
   8155 		return false;
   8156 
   8157 	for (i = 0; i < ending.length; ++i) {
   8158 		const int j = i + delta;
   8159 		if (tolower(name.string[j]) != ending.string[i])
   8160 			return false;
   8161 	}
   8162 
   8163 	return true;
   8164 }
   8165 
   8166 static bool
   8167 beginswith(String name, String beginning)
   8168 {
   8169 	int i;
   8170 
   8171 	if (name.length < beginning.length)
   8172 		return false;
   8173 
   8174 	for (i = 0; i < beginning.length; ++i) {
   8175 		if (name.string[i] != beginning.string[i])
   8176 			return false;
   8177 	}
   8178 
   8179 	return true;
   8180 }
   8181 
   8182 static String
   8183 duplicatestring(String s)
   8184 {
   8185 	String copy;
   8186 
   8187 	copy.string = (char *) calloc(s.length + 1, sizeof*(s.string));
   8188 	copy.length = s.length;
   8189 
   8190 	assert(copy.string);
   8191 	strncpy(copy.string, s.string, s.length);
   8192 
   8193 	return copy;
   8194 }
   8195 #endif
   8196 
   8197 // }}}
   8198 
   8199 // @section init source {{{
   8200 
   8201 static void
   8202 initsource(Source *source, Source *parent, Compiler *compiler,
   8203 	const char *filename, FILE *file)
   8204 {
   8205 	source->filein = file;
   8206 	source->currloc.filename = filename;
   8207 	source->tok.loc.filename = filename;
   8208 	source->tabwidth = 8;
   8209 	source->haspendingenv = false;
   8210 	source->handlereplprompt = false;
   8211 
   8212 	source->pendingcount = 0;
   8213 
   8214 	source->implicitenv = myalloc(&arenas->env, Env);
   8215 
   8216 	gettok(source);
   8217 	if (getkind(source) == LINEDELIM)
   8218 		gettok(source);
   8219 
   8220 	source->compiler = compiler;
   8221 	source->parent = parent;
   8222 	if (parent)
   8223 		listappend(parent, source);
   8224 }
   8225 
   8226 static void
   8227 disposesource(Source *source)
   8228 {
   8229 	fclose(source->filein);
   8230 }
   8231 
   8232 
   8233 
   8234 // }}}
   8235 
   8236 // @section main-routine {{{
   8237 
   8238 static const char *
   8239 isolatecommand(char **string)
   8240 {
   8241 	char *commandline = *string;
   8242 	const char *command;
   8243 
   8244 	while (isspace(*commandline))
   8245 		++commandline;
   8246 
   8247 	command = commandline;
   8248 
   8249 	while (!isspace(*commandline) && *commandline)
   8250 		++commandline;
   8251 
   8252 	if (*commandline)
   8253 		*commandline = 0, ++commandline;
   8254 
   8255 	*string = commandline;
   8256 
   8257 	return command;
   8258 }
   8259 
   8260 static bool
   8261 processcommand(Source *source)
   8262 {
   8263 	char *commandline = source->line + 1;
   8264 
   8265 	const char *command = isolatecommand(&commandline);
   8266 
   8267 	if (!strcmp(command, "exit")) {
   8268 		source->line[0] = 0;
   8269 		return false;
   8270 	}
   8271 
   8272 	if (!strcmp(command, "memory")) {
   8273 		int i;
   8274 
   8275 		printf("ast-nodes:    %5u, deletes: %5u, total: %5u\n",
   8276 			arenas->node.top, poolednodecount, totalnodecount);
   8277 
   8278 		printf("type-nodes:   %5u\n", arenas->type.top);
   8279 		printf("declarations: %5u\n", arenas->decl.top);
   8280 		printf("environments: %5u\n", arenas->env.top);
   8281 
   8282 		for (i = 0; i < arenas->node.top; ++i) {
   8283 			Node *node = getalloc(&arenas->node, i);
   8284 
   8285 			if (node->kind == 0)
   8286 				continue;
   8287 
   8288 			highlight(stdout, HLINFO);
   8289 			printf("node[%u]:\n", i);
   8290 			printexpr(stdout, node, 0);
   8291 			printf("\n");
   8292 		}
   8293 
   8294 		goto finish;
   8295 	}
   8296 
   8297 	if (!strcmp(command, "delete")) {
   8298 		command = isolatecommand(&commandline);
   8299 
   8300 		if (!strcmp(command, "node")     ||
   8301 		    !strcmp(command, "ast-node") ||
   8302 		     isdigit(*command))
   8303 		{
   8304 			int i;
   8305 
   8306 			if (!isdigit(*command))
   8307 				command = isolatecommand(&commandline);
   8308 
   8309 			i = atoi(command);
   8310 
   8311 			if (i < 4096 && i >= 0) {
   8312 				Node *node = getalloc(&arenas->node, i);
   8313 
   8314 				if (node->kind != 0)
   8315 					deletenode(node);
   8316 				else
   8317 					printf("already deleted.\n");
   8318 			} else {
   8319 				fprintf(stderr, "error: invalid number.\n");
   8320 			}
   8321 		} else {
   8322 			fprintf(stderr, "error: unknown argument '%s'.\n",
   8323 				command);
   8324 		}
   8325 
   8326 		goto finish;
   8327 	}
   8328 
   8329 	fprintf(stderr, "error: unknown command '%s'.\n", command);
   8330 finish:
   8331 	return mygetline(source);
   8332 }
   8333 
   8334 static void
   8335 handlelineending(Source *source);
   8336 
   8337 char bundlenamebuffer[1024 * 4];
   8338 int bundlenamelength = 0;
   8339 
   8340 static void
   8341 processfile(Source *source, CodeGen *cg);
   8342 
   8343 static bool
   8344 processtopleveluse(Source *source, SrcLoc *loc,
   8345 		const int bundlepath[], int count)
   8346 {
   8347 	static const char prefix[] = "arialib/";
   8348 	static const char suffix[] = ".co";
   8349 
   8350 	FILE *importfile = NULL;
   8351 	const char *filename = NULL;
   8352 	Source *curr = NULL;
   8353 
   8354 	int i;
   8355 
   8356 	if (sizeof(prefix) - 1 > sizeof(bundlenamebuffer) - 1)
   8357 		goto errorlength;
   8358 
   8359 	bundlenamelength = sizeof(prefix) - 1;
   8360 	memcpy(bundlenamebuffer, prefix, sizeof(prefix) - 1);
   8361 
   8362 	for (i = 0; i < count; ++i) {
   8363 		const int key = bundlepath[i];
   8364 		const char *string = getstring(idents, key);
   8365 		const int length = getlength(idents, key);
   8366 
   8367 		if (length + bundlenamelength > sizeof(bundlenamebuffer) - 1)
   8368 			goto errorlength;
   8369 
   8370 		memcpy(bundlenamebuffer + bundlenamelength, string, length);
   8371 		bundlenamelength += length;
   8372 
   8373 		if (i >= count - 1)
   8374 			continue;
   8375 
   8376 		if (bundlenamelength + 1 > sizeof(bundlenamebuffer) - 1)
   8377 			goto errorlength;
   8378 		
   8379 		bundlenamebuffer[bundlenamelength++] = '/';
   8380 	}
   8381 
   8382 	if (bundlenamelength + sizeof(suffix) - 1 > sizeof(bundlenamebuffer) - 1)
   8383 		goto errorlength;
   8384 
   8385 	memcpy(bundlenamebuffer + bundlenamelength, suffix, sizeof(suffix) - 1);
   8386 	bundlenamelength += sizeof(suffix) - 1;
   8387 	bundlenamebuffer[bundlenamelength] = '\0';
   8388 
   8389 	/* check for cyclic import */
   8390 	for (curr = source; curr; curr = curr->parent) {
   8391 		if (!strcmp(curr->currloc.filename, bundlenamebuffer)) {
   8392 			error("cyclic import of file '%s'", bundlenamebuffer);
   8393 			return false;
   8394 		}
   8395 	}
   8396 
   8397 	filename = calloc(bundlenamelength + 1, sizeof*(bundlenamebuffer));
   8398 
   8399 	if (!filename) {
   8400 		error(loc, "out of memory");
   8401 		return false;
   8402 	}
   8403 
   8404 	memcpy(filename, bundlenamebuffer, bundlenamelength);
   8405 
   8406 	importfile = fopen(filename, "r");
   8407 
   8408 	if (!importfile) {
   8409 		error(loc, "could not open bundle file '%s'", filename);
   8410 		return false;
   8411 	}
   8412 
   8413 	warn(loc, "using bundle '%s'", filename);
   8414 
   8415 	curr = calloc(1, sizeof*(curr));
   8416 	initsource(curr, source, source->compiler, filename, importfile);
   8417 	processfile(curr, &source->compiler->cg);
   8418 	disposesource(curr);
   8419 
   8420 	free(filename);
   8421 
   8422 	return true;
   8423 
   8424 errorlength:
   8425 	error(loc, "bundle path is too long");
   8426 	return false;
   8427 }
   8428 
   8429 static bool
   8430 isnodepending(Source *source, Node *ast)
   8431 {
   8432 	Decl *decl;
   8433 
   8434 	if (ast->kind != ADECL)
   8435 		return false;
   8436 
   8437 	decl = ast->u.declref;
   8438 	if (decl->kind != DFUNCTION)
   8439 		return false;
   8440 
   8441 	assert(decl->contentenv);
   8442 	return decl->contentenv->pending;
   8443 }
   8444 
   8445 static Node *
   8446 toplevel(Source *source, Block *block)
   8447 {
   8448 	Node *ast;
   8449 
   8450 redo:
   8451 	readannots(source);
   8452 	if (getkind(source) == KBUNDLE) {
   8453 		SrcLoc loc = *getloc(source);
   8454 #if 0
   8455 		int bundlekey = 0;
   8456 		gettok(source);
   8457 		while (getkind(source) == IDENT) {
   8458 			char *name = getstring(idents, source->tok.u.key);
   8459 			int length = getlength(idents, source->tok.u.key);
   8460 
   8461 			/* @fixme check name length */
   8462 			memcpy(bundlenamebuffer + bundlenamelength, name, length);
   8463 			bundlenamelength += length;
   8464 			gettok(source);
   8465 			bundlenamebuffer[bundlenamelength] = '\0';
   8466 
   8467 			if (getkind(source) != ODISP)
   8468 				break;
   8469 
   8470 			gettok(source);
   8471 			bundlenamebuffer[bundlenamelength++] = '_';
   8472 			bundlenamebuffer[bundlenamelength] = '\0';
   8473 		}
   8474 
   8475 		if (bundlenamelength) {
   8476 			bundlekey = getstringkey(&idents, bundlenamebuffer,
   8477 				bundlenamelength);
   8478 			assert(source->currenv);
   8479 			source->currenv->bundle = makedecl(source, bundlekey,
   8480 				DBUNDLE);
   8481 			source->currenv->loc = loc;
   8482 		}
   8483 #else
   8484 		Decl *bundle = NULL;
   8485 		gettok(source);
   8486 		while (getkind(source) == IDENT) {
   8487 			const int bundlekey = source->tok.u.key;
   8488 
   8489 			assert(source->currenv);
   8490 			bundle = makebundle(source, bundlekey, bundle);
   8491 
   8492 			gettok(source);
   8493 
   8494 			if (getkind(source) != ODISP)
   8495 				break;
   8496 
   8497 			gettok(source);
   8498 		}
   8499 
   8500 		if (bundle) {
   8501 			source->currenv->bundle = bundle;
   8502 			source->currenv->loc = loc;
   8503 		} else {
   8504 			/* @note is this correct? */
   8505 			source->currenv->bundle = NULL;
   8506 		}
   8507 #endif
   8508 
   8509 		handlelineending(source);
   8510 		goto redo;
   8511 	}
   8512 
   8513 	if (getkind(source) == KUSE) {
   8514 		int bundlepath[64];
   8515 		int bundlepathtop = 0;
   8516 
   8517 		SrcLoc loc = *getloc(source);
   8518 
   8519 		gettok(source);
   8520 		while (getkind(source) == IDENT) {
   8521 			const int bundlekey = source->tok.u.key;
   8522 
   8523 			bundlepath[bundlepathtop++] = bundlekey;
   8524 
   8525 			gettok(source);
   8526 
   8527 			if (getkind(source) != ODISP)
   8528 				break;
   8529 
   8530 			gettok(source);
   8531 		}
   8532 
   8533 		handlelineending(source);
   8534 
   8535 		processtopleveluse(source, &loc, bundlepath, bundlepathtop);
   8536 		goto redo;
   8537 	}
   8538 	ast = exprlist(source, false, NULL);
   8539 	/* ast = readexpr(source, PSTART); */
   8540 	/*
   8541 	printast(ast, 0);
   8542 	printf("\n");
   8543 	*/
   8544 	if ((ast->kind != ADECL
   8545 	||  !ast->u.payload
   8546 	||  ast->u.payload->kind != ASCOPE)
   8547 	&&  !isnodepending(source, ast))
   8548 	{
   8549 		ast = typecheck(source->currenv, ast);
   8550 		ast = foldexpr(source->currenv, ast);
   8551 		dataflow(block, ast);
   8552 	}
   8553 	ast = extractnestedfunctions(source->currenv, ast);
   8554 
   8555 	return ast;
   8556 }
   8557 
   8558 static void
   8559 processpendingenvs(Source *source, Block *block)
   8560 {
   8561 	Env *p;
   8562 
   8563 	for (p = source->pendingenvhead; p; p = p->pendingnext) {
   8564 		if (p->stmts) {
   8565 			p->stmts = typecheck(source->currenv, p->stmts);
   8566 			p->stmts = foldexpr(source->currenv, p->stmts);
   8567 			dataflow(block, p->stmts);
   8568 
   8569 			/* debug prints: */
   8570 			highlight(stdout, HLINFO);
   8571 			printf("statements:\n");
   8572 			highlight(stdout, HLNONE);
   8573 			printexpr(stdout, p->stmts, 1);
   8574 
   8575 			highlight(stdout, HLINFO);
   8576 			fputs(" : ", stdout);
   8577 			printtype(stdout, p->stmts->type, 0);
   8578 			highlight(stdout, HLNONE);
   8579 
   8580 			printf("\n");
   8581 		}
   8582 	}
   8583 
   8584 }
   8585 
   8586 static void
   8587 handlelineending(Source *source)
   8588 {
   8589 	if (getkind(source) == LINEDELIM) {
   8590 		if (source->filein == stdin) {
   8591 			highlight(stdout, HLPROMPT);
   8592 			printf("> ");
   8593 			highlight(stdout, HLNONE);
   8594 			source->handlereplprompt = false;
   8595 		}
   8596 		gettok(source);
   8597 	} else if (getkind(source) == SEMIDELIM) {
   8598 		gettok(source);
   8599 	}
   8600 
   8601 	if (source->lastkind != SEMIDELIM && source->lastkind != LINEDELIM){
   8602 		error(getloc(source), "expected new line");
   8603 		while (getkind(source) != SEMIDELIM &&
   8604 		       getkind(source) != LINEDELIM &&
   8605 		       getkind(source) != 0)
   8606 		{
   8607 			gettok(source);
   8608 		}
   8609 
   8610 		if (source->filein == stdin) {
   8611 			highlight(stdout, HLPROMPT);
   8612 			printf("> ");
   8613 			highlight(stdout, HLNONE);
   8614 			source->handlereplprompt = false;
   8615 		}
   8616 
   8617 		if (getkind(source) != 0)
   8618 			gettok(source);
   8619 	}
   8620 }
   8621 
   8622 static void
   8623 makeintrinsic(Source *source, const char *name, Type *type, bool isfunction)
   8624 {
   8625 	Decl *r;
   8626 	const int key = getstringkey(&idents, name, strlen(name));
   8627 
   8628 	if (isfunction) {
   8629 		r = makedecl(source, key, DFUNCTION);
   8630 		r->type = maketype(&source->arenas, &source->tok.loc, 
   8631 			primitive(TFUNCTION), NULL);
   8632 		r->type->u.rtarget = type;
   8633 	} else {
   8634 		r = makedecl(source, key, DVAR);
   8635 		r->type = type;
   8636 	}
   8637 }
   8638 
   8639 static void
   8640 initintrinsics(Source *source)
   8641 {
   8642 	Type *tint = primitive(TINT);
   8643 	Type *tvoid = primitive(TVOID);
   8644 	Type *voidptr = maketype(&source->arenas, &source->tok.loc,
   8645 			primitive(TPTR), primitive(TVOID));
   8646 
   8647 	#define intfunc(name, rtype) \
   8648 		makeintrinsic(source, name, rtype, true)
   8649 
   8650 	intfunc("puts", tint);
   8651 	intfunc("printf", tint);
   8652 	intfunc("vprintf", tint);
   8653 	intfunc("fprintf", tint);
   8654 	intfunc("vfprintf", tint);
   8655 	intfunc("sprintf", tint);
   8656 	intfunc("vsprintf", tint);
   8657 	intfunc("fopen", voidptr);
   8658 	intfunc("ftell", tint);
   8659 	intfunc("fseek", tint);
   8660 	intfunc("fread", tint);
   8661 	intfunc("fwrite", tint);
   8662 	intfunc("fflush", tint);
   8663 	intfunc("fclose", tint);
   8664 
   8665 	intfunc("calloc", voidptr);
   8666 	intfunc("malloc", voidptr);
   8667 	intfunc("realloc", voidptr);
   8668 
   8669 	intfunc("free", tvoid);
   8670 
   8671 	makeintrinsic(source, "SEEK_SET", tint, false);
   8672 	makeintrinsic(source, "SEEK_CUR", tint, false);
   8673 	makeintrinsic(source, "SEEK_END", tint, false);
   8674 
   8675 	#undef intfunc
   8676 }
   8677 
   8678 static void
   8679 processfile(Source *source, CodeGen *cg)
   8680 {
   8681 	Env *save;
   8682 	Block *block;
   8683 
   8684 	pushenv(source, STOPLEVEL);
   8685 	block = makeblock(BTOPLEVEL, source->currenv);
   8686 	appendconduct(block, CSCOPE, NULL);
   8687 
   8688 	initintrinsics(source);
   8689 
   8690 	save = cg->env;
   8691 	cg->env = source->currenv;
   8692 	while (getkind(source) != 0) {
   8693 		/* printf("token:%i:%i: %c '%.*s'\n", lastline, lastcol + 1,
   8694 				tok.u.id, currcol - lastcol, line + lastcol);*/
   8695 		Node *ast = toplevel(source, block);
   8696 
   8697 		highlight(stdout, HLINFO);
   8698 		printf("number of nested functions: %u\n", extractedtop - 1);
   8699 		highlight(stdout, HLNONE);
   8700 
   8701 		if (source->filein == stdin) {
   8702 			highlight(stdout, HLINFO);
   8703 			fputs("= ", stdout);
   8704 			highlight(stdout, HLNONE);
   8705 		}
   8706 
   8707 		printexpr(stdout, ast, 0);
   8708 		highlight(stdout, HLNONE);
   8709 
   8710 		if (source->filein == stdin) {
   8711 			highlight(stdout, HLINFO);
   8712 			fputs(" : ", stdout);
   8713 			printtype(stdout, ast->type, 0);
   8714 			highlight(stdout, HLNONE);
   8715 		}
   8716 		printf("\n");
   8717 
   8718 		cgtoplevel(source, ast, cg);
   8719 		handlelineending(source);
   8720 	}
   8721 
   8722 	highlight(stdout, HLINFO);
   8723 	puts("dump pending environments ...");
   8724 	highlight(stdout, HLNONE);
   8725 
   8726 	processpendingenvs(source, block);
   8727 	cgtoplevelfinish(source, cg);
   8728 	/* dfpopconduct(); */
   8729 	popenv(source);
   8730 
   8731 	highlight(stdout, HLINFO);
   8732 	printf("exiting with %u errors and %u warnings ...\n",
   8733 		errorcount, warningcount);
   8734 	highlight(stdout, HLNONE);
   8735 	cg->env = save;
   8736 }
   8737 
   8738 int
   8739 main(int argc, char **argv)
   8740 {
   8741 	Compiler compiler = {};
   8742 	Source *source = &testsource;
   8743 	arenas = &source->arenas;
   8744 
   8745 	initkeywords();
   8746 	initstrmap(&idents);
   8747 	initstrmap(&strings);
   8748 
   8749 	auxthen = getstringkey(&idents, "then", 4);
   8750 	auxin   = getstringkey(&idents, "in", 2);
   8751 	auxto   = getstringkey(&idents, "to", 2);
   8752 	auxstep = getstringkey(&idents, "step", 4);
   8753 
   8754 	auxself = getstringkey(&idents, "self", 4);
   8755 
   8756 	if (argc >= 2) {
   8757 		initsource(source, NULL, &compiler,
   8758 			argv[1], fopen(argv[1], "rb"));
   8759 		assert(source->filein);
   8760 	} else {
   8761 		highlight(stdout, HLPROMPT);
   8762 		printf("> ");
   8763 		highlight(stdout, HLNONE);
   8764 		initsource(source, NULL, &compiler, "<stdin>", stdin);
   8765 	}
   8766 
   8767 	cginit(&compiler.cg, fopen("out.c", "wb"));
   8768 	processfile(source, &compiler.cg);
   8769 	fclose(compiler.cg.out);
   8770 
   8771 	highlight(stdout, HLINFO);
   8772 	printf("number of nodes:        % 6zu\n", arenas->node.top);
   8773 	printf("number of types:        % 6zu\n", arenas->type.top);
   8774 	printf("number of environments: % 6zu\n", arenas->env.top);
   8775 	printf("number of declarations: % 6zu\n", arenas->decl.top);
   8776 	printf("number of annotations:  % 6zu\n", arenas->annot.top);
   8777 	printf("number of dockets:      % 6zu\n", arenas->docket.top);
   8778 	printf("number of records:      % 6zu\n", arenas->record.top);
   8779 	printf("number of fields:       % 6zu\n", arenas->field.top);
   8780 	printf("number of blocks:       % 6zu\n", arenas->block.top);
   8781 	printf("number of conducts:     % 6zu\n", arenas->conduct.top);
   8782 	printf("number of gists:        % 6zu\n", arenas->gist.top);
   8783 	highlight(stdout, HLNONE);
   8784 	printf("\x1b[0m");
   8785 
   8786 	/* fclose(source->filein); */
   8787 	/* disposestrmap(&strings); */
   8788 	/* disposestrmap(&idents); */
   8789 
   8790 	return !!errorcount;
   8791 }
   8792 
   8793 // }}}