Aria

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

compiler.c (175451B)


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