From 8dd7aa293fdaaf5808736214a06ff121121300d5 Mon Sep 17 00:00:00 2001 From: David Manura Date: Tue, 13 Dec 2011 21:55:08 +0530 Subject: [PATCH] Elminate loadstring. Do parsing manually in complex.to. String syntax has changed slightly. Suggested by Satheesh. --- doc/complex_changelog.txt | 4 ++ lua/complex.lua | 108 +++++++++++++++++++------------------- test/test_complex.lua | 33 +++++++++--- 3 files changed, 83 insertions(+), 62 deletions(-) diff --git a/doc/complex_changelog.txt b/doc/complex_changelog.txt index b4c4017..0683033 100644 --- a/doc/complex_changelog.txt +++ b/doc/complex_changelog.txt @@ -1,5 +1,9 @@ complex changelog +v 0.3.3: 2011-12-13 + - Elminate loadstring. Do parsing manually in complex.to. + String syntax has changed slightly. + v 0.3.2: 2011-12-03 - Add _VERSION diff --git a/lua/complex.lua b/lua/complex.lua index 1edd798..cf93934 100644 --- a/lua/complex.lua +++ b/lua/complex.lua @@ -59,16 +59,61 @@ DOWNLOAD/INSTALL --/////////////-- -- link to complex table -local complex = {_TYPE='module', _NAME='complex', _VERSION='0.3.2.20111203'} +local complex = {_TYPE='module', _NAME='complex', _VERSION='0.3.3.20111212'} -- link to complex metatable local complex_meta = {} +-- helper functions for parsing complex number strings. +local function parse_scalar(s, pos0) + local x, n, pos = s:match('^([+-]?[%d%.]+)(.?)()', pos0) + if not x then return end + if n == 'e' or n == 'E' then + local x2, n2, pos2 = s:match('^([+-]?%d+)(.?)()', pos) + if not x2 then error 'number format error' end + x = tonumber(x..n..x2) + if not x then error 'number format error' end + return x, n2, pos2 + else + x = tonumber(x) + if not x then error 'number format error' end + return x, n, pos + end +end +local function parse_component(s, pos0) + local x, n, pos = parse_scalar(s, pos0) + if not x then + local x2, n2, pos2 = s:match('^([+-]?)(i)()$', pos0) + if not x2 then error 'number format error' end + return (x2=='-' and -1 or 1), n2, pos2 + end + if n == '/' then + local x2, n2, pos2 = parse_scalar(s, pos) + x = x / x2 + return x, n2, pos2 + end + return x, n, pos +end +local function parse_complex(s) + local x, n, pos = parse_component(s, 1) + if n == '+' or n == '-' then + local x2, n2, pos2 = parse_component(s, pos) + if n2 ~= 'i' or pos2 ~= #s+1 then error 'number format error' end + if n == '-' then x2 = - x2 end + return x, x2 + elseif n == '' then + return x, 0 + elseif n == 'i' then + if pos ~= #s+1 then error 'number format error' end + return 0, x + else + error 'number format error' + end +end + -- complex.to( arg ) -- return a complex number on success -- return nil on failure -local _retone = function() return 1 end -local _retminusone = function() return -1 end function complex.to( num ) -- check for table type if type( num ) == "table" then @@ -88,55 +133,8 @@ function complex.to( num ) return setmetatable( { isnum,0 }, complex_meta ) end if type( num ) == "string" then - -- check for real and complex - -- number chars [%-%+%*%^%d%./Ee] - local real,sign,imag = string.match( num, "^([%-%+%*%^%d%./Ee]*%d)([%+%-])([%-%+%*%^%d%./Ee]*)i$" ) - if real then - if string.lower(string.sub(real,1,1)) == "e" - or string.lower(string.sub(imag,1,1)) == "e" then - return - end - if imag == "" then - if sign == "+" then - imag = _retone - else - imag = _retminusone - end - elseif sign == "+" then - imag = loadstring("return tonumber("..imag..")") - else - imag = loadstring("return tonumber("..sign..imag..")") - end - real = loadstring("return tonumber("..real..")") - if real and imag then - return setmetatable( { real(),imag() }, complex_meta ) - end - return - end - -- check for complex - local imag = string.match( num,"^([%-%+%*%^%d%./Ee]*)i$" ) - if imag then - if imag == "" then - return setmetatable( { 0,1 }, complex_meta ) - elseif imag == "-" then - return setmetatable( { 0,-1 }, complex_meta ) - end - if string.lower(string.sub(imag,1,1)) ~= "e" then - imag = loadstring("return tonumber("..imag..")") - if imag then - return setmetatable( { 0,imag() }, complex_meta ) - end - end - return - end - -- should be real - local real = string.match( num,"^(%-*[%d%.][%-%+%*%^%d%./Ee]*)$" ) - if real then - real = loadstring( "return tonumber("..real..")" ) - if real then - return setmetatable( { real(),0 }, complex_meta ) - end - end + local real, imag = parse_complex(num) + return setmetatable( { real, imag }, complex_meta ) end end @@ -170,7 +168,7 @@ end -- complex.convpolardeg( r, phi ) -- convert polar coordinates ( r*e^(i*phi) ) to carthesic complex number -- r (radius) is a number --- phi must be in degrees; e.g. [0° - 360°] +-- phi must be in degrees; e.g. [0 - 360 deg] function complex.convpolardeg( radius, phi ) phi = phi/180 * math.pi return setmetatable( { radius * math.cos( phi ), radius * math.sin( phi ) }, complex_meta ) @@ -219,7 +217,7 @@ end -- complex.polardeg( cx ) -- from complex number to polar coordinates --- output in degrees; [-180°,180°] +-- output in degrees; [-180, 180 deg] -- returns r (radius), phi (angle) function complex.polardeg( cx ) return math.sqrt( cx[1]^2 + cx[2]^2 ), math.atan2( cx[2], cx[1] ) / math.pi * 180 @@ -421,4 +419,4 @@ return complex --///////////////-- --// chillcode //-- ---///////////////-- \ No newline at end of file +--///////////////-- diff --git a/test/test_complex.lua b/test/test_complex.lua index d4d7fae..2480421 100644 --- a/test/test_complex.lua +++ b/test/test_complex.lua @@ -8,16 +8,35 @@ assert( tostring( cx ) == "2+3i" ) cx = complex ( 2 ) assert( tostring( cx ) == "2" ) assert( cx:tostring() == 2 ) -cx = complex "2^2+3/2i" -assert( tostring( cx ) == "4+1.5i" ) -cx = complex ".5-2E-3i" -assert( tostring( cx ) == "0.5-0.002i" ) -cx = complex "3i" -assert( tostring( cx ) == "3i" ) +--old:no longer supported: assert( tostring(complex '2^2+3/2i') == '4+1.5i' ) +assert( tostring( complex '.5-2E-3i' ) == '0.5-0.002i' ) +assert( tostring( complex '0' ) == '0' ) +assert( tostring( complex '10' ) == '10' ) +assert( tostring( complex '10.2' ) == '10.2' ) +assert( tostring( complex '-10.2' ) == '-10.2' ) +assert( tostring( complex '-10.2e2' ) == '-1020' ) +assert( tostring( complex '-10.2E+02' ) == '-1020' ) +assert( tostring( complex 'i' ) == 'i' ) +assert( tostring( complex '-i' ) == '-i' ) +assert( tostring( complex '3i' ) == '3i' ) +assert( tostring( complex '-3i' ) == '-3i' ) +assert( tostring( complex '0-3i' ) == '-3i' ) +assert( tostring( complex '1/+2+3/-4i' ) == '0.5-0.75i' ) +assert( tostring( complex '1e+0/2.0-1e0/2.0i' ) == '0.5-0.5i' ) +-- bad formatting +assert( not pcall(complex, '') ) +assert( not pcall(complex, '2 + 4i') ) -- space +assert( not pcall(complex, '1+2i ') ) -- space +assert( not pcall(complex, 'i+1') ) -- reversed +assert( tostring(complex'2 ') == '2' ) --ok (space, not invoking tonumber directly) +assert( not pcall(complex, '-') ) +assert( not pcall(complex, '++1') ) +assert( not pcall(complex, '1/2/3') ) -- multiple operations + +-- cx = complex "2" assert( tostring( cx ) == "2" ) assert( cx:tostring() == 2 ) -assert( complex "2 + 4i" == nil ) -- complex.new cx = complex.new( 2,3 )