; static cptr skip_linecomment ( cptr q ) noexcept { while ( * q && * q != '\x0A' ) q ++ ; return q ; } ON_INIT ( [ ] { static cstr s1 = "12 \\t4€ Af3'456" ; static cstr s2 = "/2 \\t4€ A+3\n//456'" ; static cstr s3 = "//\t\\t4€ A*3\\\n456'" ; static cstr s4 = "12 \\t4€ //3\r\n//456'" ; assert ( skip_linecomment ( s1 ) == s1 + 17 ) ; assert ( skip_linecomment ( s2 ) == s2 + 13 ) ; assert ( skip_linecomment ( s3 ) == s3 + 14 ) ; assert ( skip_linecomment ( s4 ) == s4 + 14 ) ; } ) ; static cptr skip_string ( cptr q ) throws { char delim = * q ++ ; assert ( delim == '"' || delim == '`' || delim == ''' ) ; if ( * q == delim && * ( q + 1 ) == delim ) return q + 2 ; for ( char c ; ( c = * q ++ ) && c != '\x0A' ; ) { if ( c == delim ) return q ; if ( c == '\' ) { if ( * q == '\x0D' && * ( q + 1 ) == '\x0A' ) q ++ ; if ( * q ) q ++ ; } } throw "unterminated string literal" ; } ON_INIT ( [ ] { static cstr s1 = "'12 \\t4€ Af3'456" ; static cstr s2 = "'12 \t4€ A+3\n456'" ; static cstr s3 = "'12 \"t\\'€ A*3" ; assert ( skip_string ( s1 ) == s1 + 15 ) ; try { skip_string ( s2 ) ; IERR ( ) ; } catch ( cstr ) { } try { skip_string ( s3 ) ; IERR ( ) ; } catch ( cstr ) { } } ) ; static cptr skip_longstring ( cptr q ) throws { assert ( * q == char ( 194 ) && * ( q + 1 ) == char ( 171 ) ) ; q += 2 ; while ( char c = * q ++ ) { if ( c > 0 ) { if ( c == '\' ) { if ( * q ) q ++ ; } } else if ( c == char ( 194 ) ) { c = * q ++ ; if ( c == char ( 187 ) ) return q ; if ( c == char ( 171 ) ) { q = skip_longstring ( q - 2 ) ; continue ; } } } throw "unterminated string literal" ; } ON_INIT ( [ ] { static cstr s1 = "«12 \\t4€ A¢3'456»xx" ; static cstr s2 = "«12 \t4€ A+3\n456'»»" ; static cstr s3 = "«12 \"t4«€» ««»»A*3»\n" ; static cstr s4 = "«12 \"t4«€» A*3\n" ; static cstr s5 = "«12 \"t4«» A*3\"" ; static cstr s6 = "«123\\" ; assert ( skip_longstring ( s1 ) == s1 + 22 ) ; assert ( skip_longstring ( s2 ) == s2 + 21 ) ; assert ( skip_longstring ( s3 ) == s3 + 29 ) ; try { skip_longstring ( s4 ) ; IERR ( ) ; } catch ( cstr ) { } try { skip_longstring ( s5 ) ; IERR ( ) ; } catch ( cstr ) { } try { skip_longstring ( s6 ) ; IERR ( ) ; } catch ( cstr ) { } } ) ; static cptr skip_blockcomment ( cptr q ) throws { assert ( * q == '/' && * ( q + 1 ) == '*' ) ; q += 2 ; while ( char c = * q ++ ) { if ( c > '/' ) continue ; switch ( c ) { case '*' : if ( * q == '/' ) return q + 1 ; continue ; case '/' : if ( * q == '*' ) q = skip_blockcomment ( q - 1 ) ; else if ( * q == '/' ) q = skip_linecomment ( q ) ; continue ; case ''' : case '"' : case '`' : try { q = skip_string ( q - 1 ) ; } catch ( cstr ) { } continue ; default : if ( c == char ( 194 ) && * q == char ( 171 ) ) q = skip_longstring ( q - 1 ) ; continue ; } } throw "unterminated block comment" ; } ON_INIT ( [ ] { { static cstr s = "/*123 \t \nxx**//zz" ; assert ( skip_blockcomment ( s ) == s + 14 ) ; } { static cstr s = "/*12'*/'; // xyz\n\t*/ " ; assert ( skip_blockcomment ( s ) == s + 20 ) ; } { static cstr s = "/*/*foo*/«/*\n»*/;" ; assert ( skip_blockcomment ( s ) == s + 18 ) ; } { static cstr s = "/*\n//foo*/\n//«\n*/x" ; assert ( skip_blockcomment ( s ) == s + 18 ) ; } { static cstr s = "/*it's a lie! */\n" ; assert ( skip_blockcomment ( s ) == s + 16 ) ; } { static cstr s = "/*foo\n//*/" ; try { skip_blockcomment ( s ) ; IERR ( ) ; } catch ( cstr ) { } } { static cstr s = "/*foo «*/" ; try { skip_blockcomment ( s ) ; IERR ( ) ; } catch ( cstr ) { } } { static cstr s = "/*foo \\" ; try { skip_blockcomment ( s ) ; IERR ( ) ; } catch ( cstr ) { } } } ) ; static cptr skip_spaces ( cptr q ) noexcept { for ( char c ; ( c = * q ++ ) ; ) { if ( uchar ( c ) <= ' ' ) { if ( c != '\x0A' ) continue ; else break ; } if ( c == '\' && * q == '\x0A' ) { q ++ ; continue ; } if ( c == '\' && * q == '\x0D' && * ( q + 1 ) == '\x0A' ) { q += 2 ; continue ; } if ( c == '/' && * q == '/' ) { return skip_linecomment ( q + 1 ) ; } else break ; } return q - 1 ; } ON_INIT ( [ ] { static cstr s1 = "12 \\t4€ Af3" ; static cstr s2 = "\t2" ; static cstr s3 = " \t\\\n\t \\\r\n \t \\\r\n \r\nx" ; static cstr s4 = "\\\t 12\nx" ; static cstr s5 = "\t" ; assert ( skip_spaces ( s1 ) == s1 ) ; assert ( skip_spaces ( s2 ) == s2 + 1 ) ; assert ( skip_spaces ( s3 ) == s3 + 19 ) ; assert ( skip_spaces ( s4 ) == s4 ) ; assert ( skip_spaces ( s5 ) == s5 + 1 ) ; } ) ; static cptr skip_identifier ( cptr q ) noexcept { assert ( utf8 : : is_letter ( q ) || * q == '_' ) ; do { q = utf8 : : nextchar ( q ) ; } while ( utf8 : : is_letter ( q ) || * q == '_' || utf8 : : is_dec_digit ( q ) ) ; return q ; } ON_INIT ( [ ] { { static cstr s = "L23L+" ; assert ( skip_identifier ( s ) == s + 4 ) ; } { static cstr s = "_a65qh.f" ; assert ( skip_identifier ( s ) == s + 6 ) ; } { static cstr s = "é1Ä€" ; assert ( skip_identifier ( s ) == s + 5 ) ; } { static cstr s = "кирлица+" ; assert ( skip_identifier ( s ) == s + 14 ) ; } { static cstr s = "an_0n«»" ; assert ( skip_identifier ( s ) == s + 5 ) ; } { static cstr s = "L23L\n" ; assert ( skip_identifier ( s ) == s + 4 ) ; } { static cstr s = "L23L" ; assert ( skip_identifier ( s ) == s + 4 ) ; } } ) ; inline cptr skip_decimals ( cptr p ) noexcept { while ( is_dec_digit ( * p ) ) { p ++ ; } return p ; } static cptr skip_number ( cptr q ) noexcept { if ( * q == '0' ) { if ( ( * ( q + 1 ) | 32 ) == 'x' && is_hex_digit ( * ( q + 2 ) ) ) { q += 3 ; while ( is_hex_digit ( * q ) ) { q ++ ; } return q ; } if ( ( * ( q + 1 ) | 32 ) == 'b' && is_bin_digit ( * ( q + 2 ) ) ) { q += 3 ; while ( is_bin_digit ( * q ) ) { q ++ ; } return q ; } } if ( * q == '+' || * q == '-' ) q ++ ; assert ( is_dec_digit ( * q ) ) ; q = skip_decimals ( q + 1 ) ; if ( * q == '.' && is_dec_digit ( * ( q + 1 ) ) ) { q = skip_decimals ( q + 2 ) ; } if ( ( * q | 32 ) == 'e' ) { cptr q0 = q ++ ; if ( * q == '+' || * q == '-' ) q ++ ; if ( no_dec_digit ( * q ) ) return q0 ; q = skip_decimals ( q ) ; } if ( * q == 's' || * q == 'l' ) q ++ ; return q ; } ON_INIT ( [ ] { { static cstr s = "123L+" ; assert ( skip_number ( s ) == s + 3 ) ; } { static cstr s = "0xA23L+" ; assert ( skip_number ( s ) == s + 5 ) ; } { static cstr s = "0A23h0" ; assert ( skip_number ( s ) == s + 1 ) ; } { static cstr s = "1e65qh.f" ; assert ( skip_number ( s ) == s + 4 ) ; } { static cstr s = "12.34e+5s." ; assert ( skip_number ( s ) == s + 9 ) ; } { static cstr s = "123L+" ; assert ( skip_number ( s ) == s + 3 ) ; } { static cstr s = "123L\n" ; assert ( skip_number ( s ) == s + 3 ) ; } { static cstr s = "123L" ; assert ( skip_number ( s ) == s + 3 ) ; } { static cstr s = "12.L" ; assert ( skip_number ( s ) == s + 2 ) ; } { static cstr s = "12e34" ; assert ( skip_number ( s ) == s + 5 ) ; } { static cstr s = "12.0e" ; assert ( skip_number ( s ) == s + 4 ) ; } } ) ; static cptr skip_operator ( cptr q ) noexcept { char c1 = * q ; if ( strchr ( "+-*/%><:=!&|^" , c1 ) ) { char c2 = * ( q + 1 ) ; static char o [ ] = "<<=>>=&&=||=++ -- == != >= <= !! -> /% := += -= *= /= %= &= |= ^= " ; for ( uint i = 0 ; i < NELEM ( o ) - 1 ; i += 3 ) { if ( c1 == o [ i ] && c2 == o [ i + 1 ] ) { char c3 = * ( q + 2 ) ; return c3 != ' ' && c3 == o [ i + 2 ] ? q + 3 : q + 2 ; } } } return utf8 : : nextchar ( q ) ; } ON_INIT ( [ ] { { static cstr s = ">=" ; assert ( skip_operator ( s ) == s + 2 ) ; } { static cstr s = ">> " ; assert ( skip_operator ( s ) == s + 2 ) ; } { static cstr s = ">>=" ; assert ( skip_operator ( s ) == s + 3 ) ; } { static cstr s = "<>>" ; assert ( skip_operator ( s ) == s + 1 ) ; } { static cstr s = "!a" ; assert ( skip_operator ( s ) == s + 1 ) ; } { static cstr s = "+++" ; assert ( skip_operator ( s ) == s + 2 ) ; } { static cstr s = "+--" ; assert ( skip_operator ( s ) == s + 1 ) ; } { static cstr s = "%\n" ; assert ( skip_operator ( s ) == s + 1 ) ; } { static cstr s = "%==\n" ; assert ( skip_operator ( s ) == s + 2 ) ; } { static cstr s = "¢" ; assert ( skip_operator ( s ) == s + 2 ) ; } { static cstr s = "≥" ; assert ( skip_operator ( s ) == s + 3 ) ; } { static cstr s = "&&=||=" ; assert ( skip_operator ( s ) == s + 3 ) ; } { static cstr s = "&&||=" ; assert ( skip_operator ( s ) == s + 2 ) ; } { static cstr s = "&||=" ; assert ( skip_operator ( s ) == s + 1 ) ; } } ) ; static IdfID parse_identifier ( cptr a , cptr e ) { char c = * e ; * ptr ( e ) = 0 ; IdfID id = names . add ( a ) ; * ptr ( e ) = c ; return id ; } static Value * parse_number ( cptr a , cptr e ) throws { bool s = * ( e - 1 ) == 's' ; bool l = * ( e - 1 ) == 'l' ; e -= s | l ; char c = * e ; * ptr ( e ) = 0 ; ptr z ; float128 value ; cBasicType * type = nullptr ; errno = noerror ; if ( * a == '0' && ( * ( a + 1 ) | 32 ) == 'x' ) { value = strtoull ( a + 2 , & z , 16 ) ; * ptr ( e ) = c ; uint bits = ( uint ( e - a ) - 2 ) * 4 ; type = bits <= 8 ? tushort : bits <= 16 ? tuint16 : bits <= 32 ? tuint32 : tuint64 ; if ( type -> bits > tulong -> bits ) throw "literal size exceeds sizeof ulong" ; } else if ( * a == '0' && ( * ( a + 1 ) | 32 ) == 'b' ) { value = strtoull ( a + 2 , & z , 2 ) ; * ptr ( e ) = c ; uint bits = uint ( e - a ) - 2 ; type = bits <= 8 ? tushort : bits <= 16 ? tuint16 : bits <= 32 ? tuint32 : tuint64 ; if ( type -> bits > tulong -> bits ) throw "literal size exceeds sizeof ulong" ; } else if ( skip_decimals ( a ) == e ) { value = strtoull ( a , & z , 10 ) ; * ptr ( e ) = c ; if ( errno ) goto x ; type = value <= tushort -> max ? tushort : value <= tuint16 -> max ? tuint16 : value <= tuint32 -> max ? tuint32 : tuint64 ; if ( l && type -> bits < tulong -> bits ) type = tulong ; if ( s && type -> bits > tushort -> bits ) throw "value exceeds sizeof ushort" ; if ( type -> bits > tulong -> bits ) throw "value exceeds sizeof ulong" ; } else if ( ( * a == '+' || * a == '-' ) && skip_decimals ( a + 1 ) == e ) { value = strtoll ( a , & z , 10 ) ; * ptr ( e ) = c ; if ( errno ) goto x ; type = value >= tshort -> min && value <= tshort -> max ? tshort : value >= tint16 -> min && value <= tint16 -> max ? tint16 : value >= tint32 -> min && value <= tint32 -> max ? tint32 : tint64 ; if ( l && type -> bits < tlong -> bits ) type = tlong ; if ( s && type -> bits > tshort -> bits ) throw "value exceeds sizeof short" ; if ( type -> bits > tlong -> bits ) throw "value exceeds sizeof long" ; } else { value = std : : strtold ( a , & z ) ; * ptr ( e ) = c ; if ( errno ) goto x ; type = s ? tsfloat : l ? tlfloat : tfloat ; if ( type == nullptr ) throw "the target system does not support floating point numbers" ; if ( ! type -> canRepresent ( value ) ) { cstr sfx = type -> name ; if ( type -> isInfinity ( value ) ) throw usingstr ( "%s: value reached infinity" , sfx ) ; if ( type -> isRoundToZero ( value ) ) throw usingstr ( "%s: value rounded to null" , sfx ) ; if ( type -> isDenormalized ( value ) ) { if ( type == tlfloat || type -> numLostBits ( value ) < 3 ) logline ( "%s %s: %i bits lost due to denormalization" , sfx , substr ( a , e ) , type -> numLostBits ( value ) ) ; else throw usingstr ( "%s: %i bits lost due to denormalization" , sfx , type -> numLostBits ( value ) ) ; } } } x : if ( errno ) throw strerror ( errno ) ; assert ( z == e ) ; assert ( * e == c ) ; return new Value ( type , value ) ; } static Value * parse_base256_number ( cptr a , cptr e ) throws { assert ( * a == ''' ) ; errno = noerror ; cstr s = utf8 : : unescapedstr ( substr ( a + 1 , e - 1 ) ) ; uint len = utf8 : : charcount ( s ) ; if ( len == 1 ) { uint32 n ; utf8 : : utf8_to_ucs4 ( s , & n ) ; if ( n > tchar -> basicType ( ) -> max ) throw "character code exceeds char" ; return new Value ( tchar , n ) ; } else { if ( len < 1 ) throw "base-256 literal: min. 1 character required" ; if ( len > 8 ) throw "base-256 literal: max. 8 characters allowed" ; ucs1char us [ 8 ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ; utf8 : : utf8_to_ucs1 ( s , us + 8 - len ) ; if ( errno ) throw "base-256 number: character code exceeds ucs1 (latin-1)" ; uint64 n = peek8Z ( us ) ; auto type = len <= 2 ? tuint16 : len <= 4 ? tuint32 : tuint64 ; if ( type -> bits > tulong -> bits ) throw "literal size exceeds ulong" ; return new Value ( type , n ) ; } } static Value * parse_string ( cptr a , cptr e ) throws { if ( * a == '"' ) { cstr s = utf8 : : unescapedstr ( substr ( a + 1 , e - 1 ) ) ; return new Value ( s ) ; } else if ( * a == char ( 194 ) ) { str s = substr ( a + 2 , e - 2 ) ; normalizeLinebreaks ( s ) ; s = utf8 : : unescapedstr ( s ) ; return new Value ( s ) ; } else IERR ( ) ; } Words tokenize ( cstr source , uint32 offs ) throws { Words words ; cptr a , q = source + offs ; uint32 spos ; if ( * q == char ( 239 ) && * ( q + 1 ) == char ( 187 ) && * ( q + 2 ) == char ( 191 ) ) q += 3 ; if ( * q == '#' && * ( q + 1 ) == '!' ) { q = strchr ( q , '\x0A' ) ; if ( ! q ) return words ; } while ( errors . count ( ) <= 30 ) { try { for ( a = q = skip_spaces ( q ) ; char c = * a ; a = q = skip_spaces ( q ) ) { spos = uint32 ( a - source ) ; if ( utf8 : : is_letter ( a ) || c == '_' ) { q = skip_identifier ( a ) ; words . append ( Word ( spos , parse_identifier ( a , q ) ) ) ; } else if ( is_dec_digit ( c ) ) { num : q = skip_number ( a ) ; if ( * q == 's' || * q == 'l' ) q ++ ; words . append ( Word ( spos , parse_number ( a , q ) ) ) ; } else if ( c == '"' ) { q = skip_string ( a ) ; words . append ( Word ( spos , parse_string ( a , q ) ) ) ; } else if ( c == ''' ) { q = skip_string ( a ) ; words . append ( Word ( spos , parse_base256_number ( a , q ) ) ) ; } else if ( c == char ( 194 ) && * ( a + 1 ) == char ( 171 ) ) { q = skip_longstring ( a ) ; words . append ( Word ( spos , parse_string ( a , q ) ) ) ; } else if ( c == '/' && * ( a + 1 ) == '*' ) { q = skip_blockcomment ( a ) ; continue ; } else if ( ( c == '+' || c == '-' ) && is_dec_digit ( * ( a + 1 ) ) ) { uint i = words . count ( ) ; IdfID idf ; do { idf = words [ -- i ] . idf ; } while ( idf == tNL ) ; if ( idf == tIVAL ) goto op ; if ( idf == tINCR || idf == tDECR ) goto op ; if ( idf <= tEKauf ) goto num ; goto op ; } else { op : q = skip_operator ( a ) ; words . append ( Word ( spos , parse_identifier ( a , q ) ) ) ; } } return words ; } catch ( cstr msg ) { errors . append ( SyntaxError ( spos , "%s" , msg ) ) ; } } throw AnyError ( fatalerror , "too many errors" ) ; } print ( "Hello world\n" , "Running some tests.\n" ) ; for ( int i = 0 ; i < 100 ; i ++ ) { print ( i , " " ) ; } print ( "\n" ) ; type Bar = { int a , b ; float c ; str s ; char [ ] ca ; float bar ( int x ) { return ( ( X ) * ( X ) ) ; } } uint square ( int n ) { uint m = abs ( n ) ; return m * m ; } uint root ( uint x ) { uint lo = 0 ; uint hi = min ( x , 65536 ) ; do { uint n = ( hi + lo ) / 2 ; if ( n * n > x ) { until ( hi == n ) ; hi = n ; } else { until ( lo == n ) ; lo = n ; } } return lo ; } assert ( root ( 0 ) == 0 ) ; assert ( root ( 1 ) == 1 ) ; assert ( root ( 2 ) == 1 ) ; assert ( root ( 3 ) == 1 ) ; assert ( root ( 4 ) == 2 ) ; assert ( root ( 8 ) == 2 ) ; assert ( root ( 9 ) == 3 ) ; assert ( root ( 15 ) == 3 ) ; assert ( root ( 16 ) == 4 ) ; assert ( root ( 24 ) == 4 ) ; assert ( root ( 25 ) == 5 ) ; bool [ ] isprime = new bool [ 50000 ] ; for ( uint i = 2 ; i < isprime . count ; i ++ ) isprime [ i ] = yes ; for ( uint i = 2 , imax = ( isprime . count + 1 ) / 2 ; i <= imax ; i ++ ) { if ( ! isprime [ i ] ) next ; for ( uint n = i + i ; n < isprime . count ; n += i ) { isprime [ n ] = no ; } } print ( "Primes in range 0 to " , isprime . count - 1 , "\n" ) ; for ( uint i = 0 ; i < isprime . count ; i ++ ) { if ( isprime [ i ] ) print ( i , " " ) ; } print ( "\n" ) ; bool isPrime ( uint n ) { if ( n < 3 || n % 2 == 0 ) return n == 2 ; uint imax = root ( n ) ; for ( uint i = 3 ; i <= imax ; i += 2 ) { if ( n / i * i == n ) return no ; } return yes ; } ( print ( "Validating the primes:\n" ) ; uint numerrors = 0 ; for ( uint i = 0 ; i < isprime . count ; i ++ ) { if ( isprime [ i ] != isPrime ( i ) ) { numerrors ++ ; print ( "error for number " , i , "\n" ) ; } } if ( numerrors ) print ( numerrors , " errors\n" ) ; else print ( "no errors\n" ) ;