diff --git a/include/std/math.e b/include/std/math.e index a2572b900..30265afde 100644 --- a/include/std/math.e +++ b/include/std/math.e @@ -1483,6 +1483,9 @@ end function --**** -- === Bitwise Operations -- +-- Arguments passed to bitwise operations are interpreted as sequences of bits and these sequences are operated on and the result is returned, which is another sequence of bits, is returned as a number. The numbers passed when using ix86 and ARM archetecture must use no more than 32-bits and have no fraction part. Numbers that use no more than 32-bits are numbers between -2_147_483_648 to 4_294_967_295. Numbers that have a fraction part or are outside this range will not yield the results that a calculator that uses more bits would get. +-- +-- --**** -- Signature: @@ -1507,7 +1510,7 @@ end function -- -- If you intend to manipulate full 32-bit values, you should declare your variables as atom, rather than integer. Euphoria's integer type is limited to 31-bits. -- --- Results are treated as signed numbers. They will be negative when the highest-order bit is 1. +-- Results are treated as unsigned numbers. They will never be negative. -- -- To understand the binary representation of a number you should display it in hexadecimal notation. -- Use the %x format of [[:printf]]. Using [[:int_to_bits]] is an even more direct approach. @@ -1527,10 +1530,7 @@ end function -- Example 3: -- -- a = and_bits(#FFFFFFFF, #FFFFFFFF) --- -- a is -1 --- -- Note that #FFFFFFFF is a positive number, --- -- but the result of a bitwise operation is interpreted --- -- as a signed 32-bit number, so it's negative. +-- -- a is #FFFFFFFF -- -- -- See Also: @@ -1558,7 +1558,7 @@ end function -- -- If you intend to manipulate full 32-bit values, you should declare your variables as atom, rather than integer. Euphoria's integer type is limited to 31-bits. -- --- Results are treated as signed numbers. They will be negative when the highest-order bit is 1. +-- Results are treated as unsigned numbers. They will never be negative. -- -- Example 1: -- @@ -1590,7 +1590,7 @@ end function -- -- If you intend to manipulate full 32-bit values, you should declare your variables as atom, rather than integer. Euphoria's integer type is limited to 31-bits. -- --- Results are treated as signed numbers. They will be negative when the highest-order bit is 1. +-- Results are treated as unsigned numbers. They will never be negative. -- -- Example 1: -- @@ -1628,14 +1628,14 @@ end function -- -- If you intend to manipulate full 32-bit values, you should declare your variables as atom, rather than integer. Euphoria's integer type is limited to 31-bits. -- --- Results are treated as signed numbers. They will be negative when the highest-order bit is 1. +-- Results are treated as unsigned numbers. They will never be negative. -- --- A simple equality holds for an atom ##a##: ##a + not_bits(a) = -1##. +-- A simple equality holds for an atom ##a##: ##a + not_bits(a) + 1 = power(2,32)##. -- -- Example 1: -- -- a = not_bits(#000000F7) --- -- a is -248 (i.e. FFFFFF08 interpreted as a negative number) +-- -- a is #FFFFFF08 (interpreted as a positive number) -- -- -- See Also: @@ -1662,20 +1662,26 @@ end function -- -- Example 1: -- --- ? shift_bits((7, -3) --> 56 --- ? shift_bits((0, -9) --> 0 --- ? shift_bits((4, -7) --> 512 --- ? shift_bits((8, -4) --> 128 --- ? shift_bits((0xFE427AAC, -7) --> 0x213D5600 --- ? shift_bits((-7, -3) --> -56 which is 0xFFFFFFC8 --- ? shift_bits((131, 0) --> 131 --- ? shift_bits((184.464, 0) --> 184 --- ? shift_bits((999_999_999_999_999, 0) --> -1530494977 which is 0xA4C67FFF --- ? shift_bits((184, 3) -- 23 --- ? shift_bits((48, 2) --> 12 --- ? shift_bits((121, 3) --> 15 --- ? shift_bits((0xFE427AAC, 7) --> 0x01FC84F5 --- ? shift_bits((-7, 3) --> 0x1FFFFFFF +-- ? shift_bits(7, -3) --> shift_bits(0b111, -3) -> 0b111000 (which is 56) +-- ? shift_bits(0, -9) --> shift_bits(0b0, -9) -> 0b0000000000 -> 0 +-- ? shift_bits(4, -7) --> shift_bits(0b100, -7) -> 0b1000000000 (which is 512) +-- ? shift_bits(8, -4) --> shift_bits(0b1000, -4) -> 0b1000_0000 (which is 128) +-- ? shift_bits(0xFE427AAC, -7) --> shift_bits(0b11111110010000100111101010101100, -7) +-- --> 0b00100001001111010101011000000000 +-- -- (which is 557_667_840) +-- ? shift_bits(-7, -3) --> +-- --> shift_bits(0b11111111111111111111111111111001, -3) +-- --> 0b11111111111111111111111111001000 ( which is 4_294_967_240) +-- ? shift_bits(131, 0) --> 131 +-- ? shift_bits(184.464, 0) --> 184 +-- ? shift_bits(999_999_999_999_999, 0) --> 0xA4C67FFF +-- ? shift_bits(184, 3) -- 23 +-- ? shift_bits(48, 2) --> 12 +-- ? shift_bits(121, 3) --> 15 +-- ? shift_bits(0xFE427AAC, 7) --> 0x01FC84F5 +-- ? shift_bits(-7, 3) --> 0x1FFFFFFF (which is 536_870_911) +-- --> shift_bits(0b11111111111111111111111111111001, 3) +-- --> 0b00011111111111111111111111111111 ( which is 536_870_911) -- ? shift_bits({48, 121}, 2) --> {12, 30} -- -- @@ -1739,13 +1745,13 @@ end function -- ? rotate_bits(4, -7) --> 512 -- ? rotate_bits(8, -4) --> 128 -- ? rotate_bits(0xFE427AAC, -7) --> 0x213D567F --- ? rotate_bits(-7, -3) --> -49 which is 0xFFFFFFCF +-- ? rotate_bits(-7, -3) --> 4_294_967_247 which is 0xFFFFFFCF -- ? rotate_bits(131, 0) --> 131 -- ? rotate_bits(184.464, 0) --> 184 --- ? rotate_bits(999_999_999_999_999, 0) --> -1530494977 which is 0xA4C67FFF +-- ? rotate_bits(999_999_999_999_999, 0) --> 2_764_472_319 which is 0xA4C67FFF -- ? rotate_bits(184, 3) -- 23 -- ? rotate_bits(48, 2) --> 12 --- ? rotate_bits(121, 3) --> 536870927 +-- ? rotate_bits(121, 3) --> 536_870_927 -- ? rotate_bits(0xFE427AAC, 7) --> 0x59FC84F5 -- ? rotate_bits(-7, 3) --> 0x3FFFFFFF -- ? rotate_bits({48, 121}, 2) --> {12, 1073741854} diff --git a/include/std/net/http.e b/include/std/net/http.e index 07886b67c..544761392 100644 --- a/include/std/net/http.e +++ b/include/std/net/http.e @@ -13,10 +13,10 @@ include std/sequence.e include std/socket.e as sock include std/text.e include std/types.e - +include std/search.e include std/net/dns.e include std/net/url.e as url - +include std/get.e include euphoria/info.e ifdef not EUC_DLL then @@ -106,17 +106,23 @@ function format_base_request(sequence request_type, sequence url, object headers -- only specify the port in the request if the caller did so explicitly -- some sites, such as euphoria.pastey.net, will break otherwise + -- HTTP/1.0 lacks the host header field. Use HTTP/1.1. if noport then - request = sprintf("%s %s HTTP/1.0\r\nHost: %s\r\n", { - request_type, path, host }) + request = sprintf("%s %s HTTP/1.1\r\nHost: %s\r\n", { + request_type, path, host }) else - request = sprintf("%s %s HTTP/1.0\r\nHost: %s:%d\r\n", { - request_type, path, host, port }) + request = sprintf("%s %s HTTP/1.1\r\nHost: %s:%d\r\n", { + request_type, path, host, port }) end if integer has_user_agent = 0 integer has_connection = 0 + if sequence(parsedUrl[URL_USER]) and sequence(parsedUrl[URL_PASSWORD]) then + --request &= sprintf("%s: %s:%s\r\n", {"Authorization",parsedUrl[URL_USER],parsedUrl[URL_PASSWORD]}) + + end if + if sequence(headers) then for i = 1 to length(headers) do object header = headers[i] @@ -235,7 +241,8 @@ function execute_request(sequence host, integer port, sequence request, integer sock:socket sock = sock:create(sock:AF_INET, sock:SOCK_STREAM, 0) - if sock:connect(sock, addrinfo[3][1], conn_port) != sock:OK then + if sock:connect(sock, addrinfo[3][1], port) != sock:OK then + sock:close(sock) return ERR_CONNECT_FAILED end if @@ -262,6 +269,7 @@ function execute_request(sequence host, integer port, sequence request, integer -- a disconnect. exit "top" else + sock:close(sock) return ERR_RECEIVE_FAILED end if end if @@ -299,11 +307,31 @@ function execute_request(sequence host, integer port, sequence request, integer end if end while + sock:close(sock) return { headers, content } end function --**** -- === Configuration Routines +--@nodoc@ +-- When returned headers redirect to another url, return a fully +-- qualified proper url. +function redirect_url(sequence request, sequence headers) + for i = 1 to length(headers) do + sequence headers_i = headers[i] + if equal(headers_i[1],"location") then + sequence new_url = headers_i[2] + if new_url[1] = '/' then + if not find(request[R_PORT], {0,""}) then + new_url = ":" & request[R_PORT] & new_url + end if + new_url = "http://" & request[R_HOST] & new_url + end if + return new_url + end if + end for + return sprintf("http://%s:%s/%s", { request[R_HOST], request[R_PORT], request[R_PATH] }) +end function sequence proxy_ip = {} integer proxy_port = 0 @@ -378,71 +406,102 @@ end procedure -- See Also: -- [[:http_get]] -- - public function http_post(sequence url, object data, object headers = 0, natural follow_redirects = 10, natural timeout = 15) + if not sequence(data) or length(data) = 0 then return ERR_INVALID_DATA end if - object request = format_base_request("POST", url, headers) - if atom(request) then - return request - end if - - integer data_type - if ascii_string(data) or sequence(data[1]) then - data_type = FORM_URLENCODED - else - if data[1] < 1 or data[1] > 2 then - return ERR_INVALID_DATA_ENCODING + object content, request + sequence content_1 + while follow_redirects > 0 and length(content)=2 and length(content_1) >= 1 and length(content_1[1]) >= 2 and equal(content_1[2][2], "303") with entry do + follow_redirects -= 1 + --sequence http_response_code = content[1][1][2] + -- 301, 302, 307 : must not be redirected without user interaction (RFC 2616) + url = redirect_url(request, content_1) + entry + + request = format_base_request("POST", url, headers) + if atom(request) then + return request end if - - data_type = data[1] - data = data[2] - end if - - -- data now contains either a string sequence already encoded or - -- a sequence of key/value pairs to be encoded. We know the length - -- is greater than 0, so check the first element to see if it's a - -- sequence or an atom. That will tell us what we have. - -- - -- If we have key/value pairs then we will need to encode that data - -- according to our data_type. - - sequence content_type = ENCODING_STRINGS[data_type] - if sequence(data[1]) then - -- We have key/value pairs - if data_type = FORM_URLENCODED then - data = form_urlencode(data) + + integer data_type + if ascii_string(data) or sequence(data[1]) then + data_type = FORM_URLENCODED else - sequence boundary = random_boundary(20) - content_type &= "; boundary=" & boundary - data = multipart_form_data_encode(data, boundary) + if data[1] < 1 or data[1] > 2 then + return ERR_INVALID_DATA_ENCODING + end if + + data_type = data[1] + data = data[2] end if - end if - - request[R_REQUEST] &= sprintf("Content-Type: %s\r\n", { content_type }) - request[R_REQUEST] &= sprintf("Content-Length: %d\r\n", { length(data) }) - request[R_REQUEST] &= "\r\n" - request[R_REQUEST] &= data - - object content = execute_request(request[R_HOST], request[R_PORT], request[R_REQUEST], timeout) - if follow_redirects and length(content)=2 then - sequence content_1 = content[1] - if length(content_1) >= 1 and length(content_1[1]) >= 2 and equal(content_1[2][2], "303") then - --sequence http_response_code = content[1][1][2] - -- 301, 302, 307 : must not be redirected without user interaction (RFC 2616) - for i = 1 to length(content_1) do - sequence headers_i = content_1[i] - if equal(headers_i[1],"location") then - return http_get(headers_i[2], headers, follow_redirects-1, timeout) - end if - end for + + -- data now contains either a string sequence already encoded or + -- a sequence of key/value pairs to be encoded. We know the length + -- is greater than 0, so check the first element to see if it's a + -- sequence or an atom. That will tell us what we have. + -- + -- If we have key/value pairs then we will need to encode that data + -- according to our data_type. + + sequence content_type = ENCODING_STRINGS[data_type] + if sequence(data[1]) then + -- We have key/value pairs + if data_type = FORM_URLENCODED then + data = form_urlencode(data) + else + sequence boundary = random_boundary(20) + content_type &= "; boundary=" & boundary + data = multipart_form_data_encode(data, boundary) + end if + end if + request = format_base_request("POST", url, headers) + request[R_REQUEST] &= sprintf("Content-Type: %s\r\n", { content_type }) + request[R_REQUEST] &= sprintf("Content-Length: %d\r\n", { length(data) }) + request[R_REQUEST] &= "\r\n" + request[R_REQUEST] &= data + content = execute_request(request[R_HOST], request[R_PORT], request[R_REQUEST], timeout) + if length(content) != 2 or atom(content[1]) then + return ERR_INVALID_DATA_ENCODING end if + content_1 = content[1] + end while + + -- The value in content[2] is in Chunked Transfer encoding. + -- See:http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1 + + -- We get in content[2] something like "7\r\nsucess\r\n0\r\n" + -- ^ ^ + -- | | + -- | eo_chunk + -- bo_chunk + -- + sequence chunk_size = value(content[2]) + integer bo_chunk = match({13,10}, content[2]) + 2 + + if bo_chunk = 2 or -- no size specified + chunk_size[1] != GET_SUCCESS or -- size wasn't a readable object + not integer(chunk_size[2]) or -- size wasn't an integer + bo_chunk+chunk_size[2] > length(content[2]) then -- end of chunk theoretically extends past content[2] + return ERR_INVALID_DATA_ENCODING end if + -- Using chunk_size[2] as the length causes this code to fail a unit test. + -- So don't do that. Even though that is what the RFC specifies. + + -- Don't trust chunk_size[2] instead ensure the chunk extends up to the next \r\n + + -- We use a forward search from chunk_size[2]. + integer eo_chunk = match({13,10}, content[2], bo_chunk+chunk_size[2]-1)-1 + + if eo_chunk = -1 then + return ERR_INVALID_DATA_ENCODING + end if + content[2] = content[2][bo_chunk..eo_chunk] return content end function @@ -481,30 +540,28 @@ end function public function http_get(sequence url, object headers = 0, natural follow_redirects = 10, natural timeout = 15) - object request - - request = format_base_request("GET", url, headers) + object request, content + sequence content_1 - if atom(request) then - return request - end if - - -- No more work necessary, terminate the request with our ending CR LF - request[R_REQUEST] &= "\r\n" - - object content = execute_request(request[R_HOST], request[R_PORT], request[R_REQUEST], timeout) - if follow_redirects and length(content)=2 then - sequence content_1 = content[1] - if length(content_1) >= 1 and length(content_1[1]) >= 2 and - find(content_1[1][2], {"301","302","303","307","308"}) then - for i = 1 to length(content_1) do - sequence headers_i = content_1[i] - if equal(headers_i[1],"location") then - return http_get(headers_i[2], headers, follow_redirects-1, timeout) - end if - end for + while follow_redirects > 0 and length(content_1) >= 1 and length(content_1[1]) >= 2 and + find(content_1[1][2], {"301","302","303","307","308"}) with entry do + follow_redirects -= 1 + + url = redirect_url(request, content_1) + entry + request = format_base_request("GET", url, headers) + + if atom(request) then + return request end if - end if + -- No more work necessary, terminate the request with our ending CR LF + request[R_REQUEST] &= "\r\n" + content = execute_request(request[R_HOST], request[R_PORT], request[R_REQUEST], timeout) + if length(content) != 2 then + exit + end if + content_1 = content[1] + end while return content end function diff --git a/include/std/utils.e b/include/std/utils.e index 426ea16c0..39145521f 100644 --- a/include/std/utils.e +++ b/include/std/utils.e @@ -57,6 +57,40 @@ public function iif(atom test, object ifTrue, object ifFalse) return ifFalse end function +public function assign(integer i1, object val1, + integer i2 = 0, object val2 = 0, + integer i3 = 0, object val3 = 0, + integer i4 = 0, object val4 = 0, + integer i5 = 0, object val5 = 0, + integer i6 = 0, object val6 = 0, + integer i7 = 0, object val7 = 0, + integer i8 = 0, object val8 = 0, + integer i9 = 0, object val9 = 0, + integer i10 = 0, object val10 = 0) + sequence s = {i1, val1, i2, val2, i3, val3, i4, val4, i5, val5, i6, val6, i7, val7, i8, val8, i9, val9, i10, val10} + for i = 3 to 19 by 2 do + if s[i] = 0 then + return assign_s(s[1..i-1]) + end if + end for + return assign_s(s) +end function + +function assign_s(sequence s) + integer maxi + sequence ret + maxi=0 + for i = 1 to length(s) by 2 do + if s[i] > maxi then + maxi = s[i] + end if + end for + ret = repeat(0,maxi) + for i = 1 to length(s) by 2 do + ret[s[i]] = s[i+1] + end for + return ret +end function --** -- @nodoc@ diff --git a/source/common.e b/source/common.e index f13f21450..6b386c385 100644 --- a/source/common.e +++ b/source/common.e @@ -9,6 +9,8 @@ elsedef without type_check end ifdef +with type_check + include std/os.e include std/filesys.e include std/search.e @@ -22,6 +24,7 @@ public constant DIRECT_OR_PUBLIC_INCLUDE = DIRECT_INCLUDE + PUBLIC_INCLUDE, ANY_INCLUDE = DIRECT_OR_PUBLIC_INCLUDE + INDIRECT_INCLUDE + public sequence SymTab = {} -- the symbol table public sequence known_files = {} diff --git a/source/parser.e b/source/parser.e index 482cb4cca..b77d9ecc1 100644 --- a/source/parser.e +++ b/source/parser.e @@ -3446,7 +3446,7 @@ function Global_declaration(integer type_ptr, integer scope) token tok object tsym object prevtok = 0 - symtab_index sym, valsym + symtab_index sym, valsym, prevsym = 0, deltasym = 0 integer h, count = 0 atom val = 1, usedval integer deltafunc = '+' @@ -3499,6 +3499,8 @@ function Global_declaration(integer type_ptr, integer scope) negate = 1 ptok = next_token() end if + + if ptok[T_ID] != ATOM then CompileErr( A_NUMERIC_LITERAL_WAS_EXPECTED) end if @@ -3519,7 +3521,16 @@ function Global_declaration(integer type_ptr, integer scope) end switch + if integer(delta) then + deltasym = NewIntSym(delta) + else + deltasym = NewDoubleSym(delta) + end if else + deltasym = NewIntSym(1) + if deltasym > 0 then + SymTab[deltasym][S_USAGE] = U_READ + end if putback(ptok) end if end if @@ -3572,7 +3583,7 @@ function Global_declaration(integer type_ptr, integer scope) SymTab[sym][S_USAGE] = U_WRITTEN if TRANSLATE then SymTab[sym][S_GTYPE] = TYPE_OBJECT - SymTab[sym][S_OBJ] = NOVALUE -- distinguish from literals + SymTab[sym][S_OBJ] = NOVALUE -- distinguish from literals end if valsym = Top() @@ -3603,6 +3614,8 @@ function Global_declaration(integer type_ptr, integer scope) end if end if + + -- end CONSTANT elsif type_ptr = -1 and not is_fwd_ref then -- ENUM StartSourceLine(FALSE, , COVERAGE_OVERRIDE ) @@ -3610,77 +3623,87 @@ function Global_declaration(integer type_ptr, integer scope) -- temporarily hide sym so it can't be used in defining itself buckets[SymTab[sym][S_HASHVAL]] = SymTab[sym][S_SAMEHASH] tok = next_token() - - + StartSourceLine(FALSE, , COVERAGE_OVERRIDE) emit_opnd(sym) if tok[T_ID] = EQUALS then - integer negate = 1 + Expr() + buckets[SymTab[sym][S_HASHVAL]] = sym + SymTab[sym][S_USAGE] = U_WRITTEN - tok = next_token() - if tok[T_ID] = MINUS then - negate = -1 - tok = next_token() + valsym = Top() + + if TRANSLATE then + SymTab[sym][S_GTYPE] = TYPE_OBJECT + SymTab[sym][S_OBJ] = NOVALUE -- distinguish from literals end if - if tok[T_ID] = ATOM then - valsym = tok[T_SYM] - elsif tok[T_SYM] > 0 then - tsym = SymTab[tok[T_SYM]] - if tsym[S_MODE] = M_CONSTANT then - if length(tsym) >= S_CODE and tsym[S_CODE] then - valsym = tsym[S_CODE] - - elsif not equal( tsym[S_OBJ], NOVALUE ) then - if is_integer(tsym[S_OBJ]) then - valsym = tok[T_SYM] - else - CompileErr(AN_ENUM_CONSTANT_MUST_BE_AN_INTEGER) - end if - else - CompileErr(ENUM_CONSTANTS_MUST_BE_ASSIGNED_AN_INTEGER) - end if - elsif tsym[S_OBJ] = NOVALUE then - -- forward reference - CompileErr(ENUM_FWD_REFERENCES_NOT_SUPPORTED) - else - CompileErr(INTEGER_OR_CONSTANT_EXPECTED) - - end if - else -- tok[T_ID] != ATOM and tok[T_SYM] !> 0 - CompileErr(INTEGER_OR_CONSTANT_EXPECTED) - end if - valsym = tok[T_SYM] - if not atom( SymTab[valsym][S_OBJ] ) and tsym[S_SCOPE] != SC_UNDEFINED then - CompileErr(ENUM_CONSTANTS_MUST_BE_INTEGERS) - end if - val = SymTab[valsym][S_OBJ] * negate - if is_integer(val) then - Push(NewIntSym(val)) + valsym = Top() + + emit_op(ASSIGN) + if Last_op() = ASSIGN then + valsym = get_assigned_sym() else - Push(NewDoubleSym(val)) + -- something else happened...could be a built-in + valsym = -1 end if - usedval = val - if deltafunc = '+' then - val += delta - else - val *= delta + if valsym > 0 and compare( SymTab[valsym][S_OBJ], NOVALUE ) then + -- need to remember this for select/case statements + SymTab[sym][S_CODE] = valsym end if - else - putback(tok) - if is_integer(val) then - Push(NewIntSym(val)) - else - Push(NewDoubleSym(val)) + + if TRANSLATE then + count += 1 + if count = 10 then + count = 0 + -- break up really long declarations + emit_op( RETURNT ) + end if + SymTab[sym][S_USAGE] = U_READ + valsym = get_assigned_sym() end if - usedval = val - if deltafunc = '+' then - val += delta + + else + + buckets[SymTab[sym][S_HASHVAL]] = sym + SymTab[sym][S_USAGE] = U_WRITTEN + if prevsym = 0 then + symtab_index one = NewIntSym(1) + SymTab[one][S_USAGE] = U_USED + emit_opnd(sym) + emit_opnd(one) + SymTab[sym][S_CODE] = one + emit_op(ASSIGN) + valsym = Top() else - val *= delta + emit_opnd(deltasym) + emit_opnd(prevsym) + SymTab[deltasym][S_USAGE] = U_READ + switch deltafunc do + case '+', '-' then + emit_op(reserved:PLUS) + case else + emit_op(reserved:MULTIPLY) + end switch + SymTab[Top()][S_USAGE] = U_READ + emit_opnd(sym) + emit_opnd(Top()) + emit_op(ASSIGN) + + SymTab[sym][S_USAGE] = U_READ + valsym = get_assigned_sym() end if + if valsym > 0 and compare( SymTab[valsym][S_OBJ], NOVALUE ) then + -- need to remember this for select/case statements + SymTab[sym][S_CODE] = valsym + end if + putback(tok) valsym = 0 end if + -- forbid sequences + emit_opnd(sym) + op_info1 = sym + emit_op(ATOM_CHECK) buckets[SymTab[sym][S_HASHVAL]] = sym SymTab[sym][S_USAGE] = U_WRITTEN @@ -3689,41 +3712,7 @@ function Global_declaration(integer type_ptr, integer scope) SymTab[sym][S_OBJ] = NOVALUE -- distinguish from literals end if - if valsym < 0 then - -- fwd reference - - end if - - if valsym and compare( SymTab[valsym][S_OBJ], NOVALUE ) then - -- need to remember this for select/case statements - SymTab[sym][S_CODE] = valsym - SymTab[sym][S_OBJ] = usedval - - if TRANSLATE then - -- Let the translator know about its value - SymTab[sym][S_GTYPE] = SymTab[valsym][S_GTYPE] - SymTab[sym][S_SEQ_ELEM] = SymTab[valsym][S_SEQ_ELEM] - SymTab[sym][S_OBJ_MIN] = usedval - SymTab[sym][S_OBJ_MAX] = usedval - SymTab[sym][S_SEQ_LEN] = SymTab[valsym][S_SEQ_LEN] - end if - else - SymTab[sym][S_OBJ] = usedval - if TRANSLATE then - -- Let the translator know about its value - if is_integer( usedval ) then - SymTab[sym][S_GTYPE] = TYPE_INTEGER - else - SymTab[sym][S_GTYPE] = TYPE_DOUBLE - end if - SymTab[sym][S_SEQ_ELEM] = 0 - SymTab[sym][S_OBJ_MIN] = usedval - SymTab[sym][S_OBJ_MAX] = usedval - SymTab[sym][S_SEQ_LEN] = 0 --SymTab[valsym][S_SEQ_LEN] - end if - end if - valsym = Pop() - valsym = Pop() + -- end of ENUM else -- variable SymTab[sym][S_MODE] = M_NORMAL @@ -3752,6 +3741,7 @@ function Global_declaration(integer type_ptr, integer scope) exit end if prevtok = tok + prevsym = sym end while putback(tok) return new_symbols @@ -4105,7 +4095,6 @@ procedure SubProg(integer prog_type, integer scope, integer deprecated) integer first_def_arg integer again integer type_enum - object seq_sym object i1_sym sequence enum_syms = {} integer type_enum_gline, real_gline @@ -4140,7 +4129,6 @@ procedure SubProg(integer prog_type, integer scope, integer deprecated) -- range of the enum is accepted -- as valid. i1_sym = keyfind("i1",-1) - seq_sym = NewStringSym(seq_symbol) putback(keyfind("return",-1)) putback({RIGHT_ROUND,0}) putback(i1_sym) @@ -4379,25 +4367,29 @@ procedure SubProg(integer prog_type, integer scope, integer deprecated) -- Parse a list of statements stmt_nest += 1 tok_match(RETURN) - putback({RIGHT_ROUND,0}) - putback({VARIABLE,seq_sym}) - putback({COMMA,0}) - putback(i1_sym) - putback({LEFT_ROUND,0}) - putback(keyfind("find",-1)) - if not TRANSLATE then - if OpTrace then - emit_op(ERASE_PRIVATE_NAMES) - emit_addr(CurrentSub) - end if - end if - Expr() - FuncReturn = TRUE + emit_opnd(i1_sym[T_SYM]) + emit_opnd(enum_syms[1]) + emit_op(EQUAL) + SymTab[Top()][S_USAGE] = U_USED + for ei = 2 to length(enum_syms) do + symtab_index last_comparison = Top() + emit_opnd(i1_sym[T_SYM]) + emit_opnd(enum_syms[ei]) + emit_op(EQUAL) + SymTab[Top()][S_USAGE] = U_USED + emit_opnd(Top()) + emit_opnd(last_comparison) + emit_op(OR) + SymTab[Top()][S_USAGE] = U_USED + end for + emit_opnd(Top()) emit_op(RETURNF) flush_temps() stmt_nest -= 1 InitDelete() flush_temps() + FuncReturn = TRUE + tok_match(END) else Statement_list() -- parse routine end. diff --git a/source/scanner.e b/source/scanner.e index 5b403dc08..23f1d0fde 100644 --- a/source/scanner.e +++ b/source/scanner.e @@ -1217,7 +1217,7 @@ function my_sscanf(sequence yytext) elsifdef BITS64 then mantissa = scientific_to_atom( yytext, EXTENDED ) elsedef - InternalErr( 351, "Scanning scientific notation in my_sscanf" ) + InternalErr( ERROR_IN_PARSING_SCIENTIFIC_NOTATION, "Scanning scientific notation in my_sscanf" ) end ifdef goto "floating_point_check" end if @@ -1229,8 +1229,7 @@ function my_sscanf(sequence yytext) yytext &= 0 -- end marker c = yytext[1] i = 2 - - + while c >= '0' and c <= '9' do ndigits += 1 mantissa = mantissa * 10.0 + (c - '0') @@ -1238,31 +1237,59 @@ function my_sscanf(sequence yytext) i += 1 end while - if fenv:test(FE_OVERFLOW) then - real_overflow = 1 - end if - - if c = '.' then + -- indicates whether the value the user entered was not zero + integer not_zero = 0 + if c = '.' and not fenv:test(FE_OVERFLOW) then -- get fraction c = yytext[i] i += 1 + -- backup value of dec + atom back_dec + -- the denomonator of the fraction part dec = 1.0 - atom frac = 0 + -- its backup and the numerator of the fraction part + atom num_back, num = 0 while c >= '0' and c <= '9' do ndigits += 1 - frac = frac * 10 + (c - '0') + if c != '0' then + not_zero = 1 + end if + num_back = num + num = num_back * 10 + (c - '0') + -- if num = PINF, so also will be dec in this iteration + back_dec = dec dec *= 10.0 c = yytext[i] i += 1 + if dec = PINF then + -- clear FE_OVERFLOW, for it only means there + -- are more digits after the decimal than we + -- can use to calculate a fraction. + fenv:clear(fenv:FE_OVERFLOW) + num = num_back + dec = back_dec + exit + end if end while - mantissa += frac / dec + -- keep looking for non-zero digits. + while c >= '0' and c <= '9' do + if c != '0' then + not_zero = 1 + exit + end if + c = yytext[i] + i += 1 + end while + atom frac + frac = num / dec + mantissa += frac + if frac = 0 and not_zero then + -- the literal represents a non-zero number that + -- is too small to be representable as an atom. + fenv:raise(fenv:FE_UNDERFLOW) + end if end if - if fenv:test(fenv:FE_OVERFLOW) and not real_overflow then - fenv:clear(fenv:FE_OVERFLOW) - fenv:raise(fenv:FE_UNDERFLOW) - end if - if ndigits = 0 then CompileErr(NUMBER_NOT_FORMED_CORRECTLY) -- no digits end if diff --git a/tests/t_881-1.e b/tests/t_881-1.e index 2c149588d..c4732e9ed 100644 --- a/tests/t_881-1.e +++ b/tests/t_881-1.e @@ -1,11 +1,10 @@ ---Code is: { (63)FLOOR_DIV match, (149)ASSIGN_OP_SUBS b, (145)SC2_NULL , (154)SYSTEM_EXEC foo_1__tmp_at1, (56)AND_BITS gets, (154)SYSTEM_EXEC foo_1__tmp_at1, (147)SC1_OR_IF , (151)PROFILE s0, (159)NOP function foo(integer x) return and_bits(floor(x/{#40,#08,#1}), #7) end function constant b = #AA -sequence s0 = foo(b) +sequence s0 = foo(b) include std/unittest.e diff --git a/tests/t_c_enum_strings.d/control.err b/tests/t_c_enum_strings.d/control.err index e15d07c17..c4a3e4ec2 100644 --- a/tests/t_c_enum_strings.d/control.err +++ b/tests/t_c_enum_strings.d/control.err @@ -1,17 +1,4 @@ t_c_enum_strings.e:4 -<0030>:: An enum constant must be an integer - MONDAY = "Monday", - ^ +type_check failure, MONDAY is {77'M',111'o',110'n',100'd',97'a',121'y'} ---- Defined Words --- -EU4 -EU400 -EU40000 -WINDOWS -WIN32 -WIN32_CONSOLE -UNITTEST -CRASH -EUI -------------------- diff --git a/tests/t_c_enum_strings_sneaky.d/control.err b/tests/t_c_enum_strings_sneaky.d/control.err new file mode 100644 index 000000000..5bc38f1c0 --- /dev/null +++ b/tests/t_c_enum_strings_sneaky.d/control.err @@ -0,0 +1,6 @@ +t_c_enum_strings_sneaky.e:4 +type_check failure, FLAG1 is {0,1} + + +Public & Export & Global & Local Variables + diff --git a/tests/t_c_enum_strings_sneaky.e b/tests/t_c_enum_strings_sneaky.e new file mode 100644 index 000000000..6d20f9d13 --- /dev/null +++ b/tests/t_c_enum_strings_sneaky.e @@ -0,0 +1,9 @@ +include std/unittest.e + +enum type w32flagsAndEx by *2 + FLAG1 = 0 & 1, + FLAG2 = 0 & 2, + FLAG3 = 0 & 4 +end type + +test_pass("t_c_enum_strings_sneaky") diff --git a/tests/t_c_fwd_enum_type.d/control.err b/tests/t_c_fwd_enum_type.d/control.err index 7d95a380d..8b1256562 100644 --- a/tests/t_c_fwd_enum_type.d/control.err +++ b/tests/t_c_fwd_enum_type.d/control.err @@ -1,7 +1,6 @@ t_c_fwd_enum_type.e:11 -<0331>:: Forward references are not supported for enums - THURSDAY = foo, - ^ - - +<0074>:: Errors resolving the following references: + 'foo' (t_c_fwd_enum_type.e:11) has not been declared. + THURSDAY = foo, + ^ diff --git a/tests/t_enum_expressions.e b/tests/t_enum_expressions.e new file mode 100644 index 000000000..6286c0be3 --- /dev/null +++ b/tests/t_enum_expressions.e @@ -0,0 +1,20 @@ +include std/unittest.e + +enum type numbers + one, + two, + three = two + one, + four = three + one +end type + +switch 3 do + case one then + puts(1, "one") + case two then + puts(1, "two") + case three then + puts(1, "three") +end switch + +test_pass("type enum expressions") +test_report() diff --git a/tests/t_goto_.e b/tests/t_goto_.e index b3b24fda6..2c2b233de 100644 --- a/tests/t_goto_.e +++ b/tests/t_goto_.e @@ -2,7 +2,6 @@ include std/unittest.e include std/error.e warning_file(-1) -with trace integer n,m,c n = 0 diff --git a/tests/t_literals.e b/tests/t_literals.e index c0afcdc03..af248e138 100644 --- a/tests/t_literals.e +++ b/tests/t_literals.e @@ -217,4 +217,7 @@ test_equal( "Something looks bigger than it is #2", 0, scientific_to_atom("00000 test_equal( "0b1.11111111e53", power(2,53)-1, 9007199254740991 ) test_equal( "0b1.11111111e-55", 1 - power(2,-53), 0.99999999999999988897769753748434595763683319091796875 ) +-- ridiculously long literals: +test_false("Excessively long 0 doesn't cause an error and is read as 0", 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) +test_equal("Excessively long 1/9 doesn't cause an error", 1, 9 * 0.1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111) test_report() diff --git a/tests/t_net_http.e b/tests/t_net_http.e index 3d6101305..1ade5418e 100644 --- a/tests/t_net_http.e +++ b/tests/t_net_http.e @@ -5,6 +5,9 @@ include std/math.e include std/os.e ifdef not NOINET_TESTS then + -- this gives the server user:pass of devel:devel + constant authorize_header = {"Authorization", "Basic ZGV2ZWw6ZGV2ZWw="} + object content content = http_get("http://www.iana.org/") @@ -14,10 +17,10 @@ ifdef not NOINET_TESTS then content = http_get("http://www.iana.org") assert("content readable http_get no path", length(content) > 1) test_not_equal("content non-empty with http_get no path", length(content[2]), 0) - + content = http_get("http://www.iana.org/domains/example/") if atom(content) then - test_fail("content readable from http_get with a path") + test_fail(sprintf("content readable from http_get with a path %d", {content})) else assert("content readable from http_get with a path", length(content) = 2) test_true("content correct form from http_get with a path", match("", "" & content[2])) @@ -36,7 +39,8 @@ ifdef not NOINET_TESTS then sequence data = { { "data", num } } - content = http_post("http://test.openeuphoria.org/post_test.ex", data) + content = http_post("http://test.openeuphoria.org/post_test.ex", data, + {authorize_header}) if atom(content) or length(content) < 2 then test_fail("http_post post #1") else @@ -44,9 +48,10 @@ ifdef not NOINET_TESTS then end if sequence headers = { - { "Cache-Control", "no-cache" } + { "Cache-Control", "no-cache" }, + authorize_header } - content = http_get("http://test.openeuphoria.org/post_test.txt", headers) + content = http_get("http://test.openeuphoria.org/post_test.txt", headers ) if atom(content) or length(content) < 2 then test_true("http_get with headers #2", sequence(content)) test_fail("http_get with headers #3") @@ -63,7 +68,7 @@ ifdef not NOINET_TESTS then -- Test already encoded string num = sprintf("%d", { rand_range(1000,10000) }) data = sprintf("data=%s", { num }) - content = http_post("http://test.openeuphoria.org/post_test.ex", data) + content = http_post("http://test.openeuphoria.org/post_test.ex", data, {authorize_header}) assert("http_get with headers #5", length(content) = 2) test_equal("http_get with headers #6", "success", content[2]) @@ -82,7 +87,7 @@ ifdef not NOINET_TESTS then -- post file script gets size and file parameters, calls decode_base64, and sends -- back SIZE\nDECODED_FILE_CONTENTS. The test script is written in Perl to test against -- modules we did not code, i.e. CGI and Base64 in this case. - content = http_post("http://test.openeuphoria.org/post_file.cgi", { MULTIPART_FORM_DATA, data }) + content = http_post("http://test.openeuphoria.org/post_file.cgi", { MULTIPART_FORM_DATA, data }, {authorize_header}) if atom(content) or length(content) < 2 then test_fail("multipart form file upload") else diff --git a/tests/t_socket.e b/tests/t_socket.e index fffef6b4b..7caa954b4 100644 --- a/tests/t_socket.e +++ b/tests/t_socket.e @@ -68,10 +68,10 @@ object p = pipe:exec(interpreter & " " & build_commandline( option_switches() ) if atom(p) then test_fail("could not launch temporary server") else - -- Give the server a second to actually launch - sleep(1) integer maxwait = 10 for i = 1 to maxwait do + -- Give the server up to ten seconds to actually launch + sleep(1) _ = sock:connect(socket, "127.0.0.1:"&port) if _ = 0 then exit