Mercurial Hosting > luan
changeset 1520:d9a5405a3102
try statement
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Sun, 21 Jun 2020 18:14:13 -0600 |
parents | 3ebf9781707c |
children | d3e61cd2aca0 |
files | conv.txt src/luan/cmd_line.luan src/luan/host/main.luan src/luan/impl/LuanImpl.java src/luan/impl/LuanParser.java src/luan/modules/BasicLuan.java src/luan/modules/Boot.luan src/luan/modules/Io.luan src/luan/modules/Luan.luan src/luan/modules/Rpc.luan src/luan/modules/Thread.luan src/luan/modules/http/Http_test.luan src/luan/modules/http/Server.luan src/luan/modules/http/tools/Run.luan src/luan/modules/http/tools/Shell.luan website/src/diff.html website/src/manual.html |
diffstat | 17 files changed, 183 insertions(+), 287 deletions(-) [+] |
line wrap: on
line diff
--- a/conv.txt Fri Jun 19 20:10:47 2020 -0600 +++ b/conv.txt Sun Jun 21 18:14:13 2020 -0600 @@ -1,3 +1,6 @@ +Luan.try +Luan.pcall + Thread.run_in_lock Thread.new_synchronizer
--- a/src/luan/cmd_line.luan Fri Jun 19 20:10:47 2020 -0600 +++ b/src/luan/cmd_line.luan Sun Jun 21 18:14:13 2020 -0600 @@ -2,7 +2,6 @@ local error = Luan.error local ipairs = Luan.ipairs or error() local load_file = Luan.load_file or error() -local try = Luan.try or error() local Table = require "luan:Table.luan" local pack = Table.pack or error() local unpack = Table.unpack or error() @@ -20,17 +19,14 @@ for j,v in ipairs(args) do Luan.arg[j-1] = v end - try { - function() - local main_file = load_file(file) or error("file '"..file.."' not found") - local rtn = pack( main_file( unpack(Luan.arg) ) ) - if rtn.n > 0 then - print( unpack(rtn) ) - end + try + local main_file = load_file(file) or error("file '"..file.."' not found") + local rtn = pack( main_file( unpack(Luan.arg) ) ) + if rtn.n > 0 then + print( unpack(rtn) ) end - catch = function(e) --- require "java"; e.java.printStackTrace(); - Io.print_to(Io.stderr, e ) - end - } + catch e +-- require "java"; e.java.printStackTrace(); + Io.print_to(Io.stderr, e ) + end end
--- a/src/luan/host/main.luan Fri Jun 19 20:10:47 2020 -0600 +++ b/src/luan/host/main.luan Sun Jun 21 18:14:13 2020 -0600 @@ -3,7 +3,6 @@ local error = Luan.error local type = Luan.type or error() local ipairs = Luan.ipairs or error() -local try = Luan.try or error() local Io = require "luan:Io.luan" local Rpc = require "luan:Rpc.luan" local Thread = require "luan:Thread.luan"
--- a/src/luan/impl/LuanImpl.java Fri Jun 19 20:10:47 2020 -0600 +++ b/src/luan/impl/LuanImpl.java Sun Jun 21 18:14:13 2020 -0600 @@ -258,4 +258,6 @@ return sb.toString(); } + public static void nopTry() throws LuanException {} + }
--- a/src/luan/impl/LuanParser.java Fri Jun 19 20:10:47 2020 -0600 +++ b/src/luan/impl/LuanParser.java Sun Jun 21 18:14:13 2020 -0600 @@ -322,6 +322,7 @@ || (stmt=WhileStmt()) != null || (stmt=RepeatStmt()) != null || (stmt=IfStmt()) != null + || (stmt=TryStmt()) != null || (stmt=SetStmt()) != null || (stmt=ExpressionsStmt()) != null ) { @@ -481,7 +482,7 @@ Expr expr = RequiredExpr().single(); RequiredKeyword("do"); - String fnVar = "fn"+ ++forCounter; + String fnVar = "fn" + ++forCounter; Expr fnExp = new Expr(null,false); fnExp.add( fnVar + ".call()" ); Stmts stmt = new Stmts(); @@ -591,7 +592,7 @@ parser.begin(); if( !Keyword("repeat") ) return parser.failure(null); - Stmts loop =RequiredLoopBlock(); + Stmts loop = RequiredLoopBlock(); RequiredKeyword("until"); Expr cnd = RequiredExpr().single(); Stmts stmt = new Stmts(); @@ -653,6 +654,42 @@ return parser.success( stmt ); } + int catchCounter = 0; + + private Stmts TryStmt() throws ParseException { + parser.begin(); + if( !Keyword("try") ) + return parser.failure(null); + Stmts tryBlock = RequiredBlock(); + Stmts catchBlock = null; + Stmts finallyBlock = null; + Stmts stmt = new Stmts(); + stmt.add( "try { LuanImpl.nopTry(); " ); + stmt.addAll( tryBlock ); + if( Keyword("catch") ) { + String name = Name(); + Expr exp = new Expr(Val.SINGLE,false); + String var = "e" + ++catchCounter; + exp.add( var+".table(luan)" ); + stmt.add( "} catch(LuanException "+var+") { " ); + stmt.addAll( addSymbol(name,exp) ); + catchBlock = RequiredBlock(); + stmt.addAll( catchBlock ); + popSymbols(1); + } + if( Keyword("finally") ) { + finallyBlock = RequiredBlock(); + stmt.add( "} finally { " ); + stmt.addAll( finallyBlock ); + } + RequiredEnd("end_try"); + if( catchBlock==null && finallyBlock==null ) + stmt.add( "} finally { " ); + stmt.add( "} " ); + stmt.hasReturn = finallyBlock!=null && finallyBlock.hasReturn || tryBlock.hasReturn && (catchBlock==null || catchBlock.hasReturn); + return parser.success( stmt ); + } + private Stmts SetStmt() throws ParseException { parser.begin(); List<Var> vars = new ArrayList<Var>(); @@ -1467,6 +1504,7 @@ private static final Set<String> keywords = new HashSet<String>(Arrays.asList( "and", "break", + "catch", "continue", "do", "else", @@ -1476,8 +1514,10 @@ "end_for", "end_function", "end_if", + "end_try", "end_while", "false", + "finally", "for", "function", "goto",
--- a/src/luan/modules/BasicLuan.java Fri Jun 19 20:10:47 2020 -0600 +++ b/src/luan/modules/BasicLuan.java Sun Jun 21 18:14:13 2020 -0600 @@ -193,54 +193,6 @@ return obj instanceof LuanFunction ? (LuanFunction)obj : null; } - public static Object try_(LuanTable blocks,Object... args) throws LuanException { - Utils.checkNotNull(blocks); - Object obj = blocks.get(1); - if( obj == null ) - throw new LuanException("missing 'try' value"); - if( !(obj instanceof LuanFunction) ) - throw new LuanException("bad 'try' value (function expected, got "+Luan.type(obj)+")"); - LuanFunction tryFn = (LuanFunction)obj; - LuanFunction catchFn = null; - obj = blocks.get("catch"); - if( obj != null ) { - if( !(obj instanceof LuanFunction) ) - throw new LuanException("bad 'catch' value (function expected, got "+Luan.type(obj)+")"); - catchFn = (LuanFunction)obj; - } - LuanFunction finallyFn = null; - obj = blocks.get("finally"); - if( obj != null ) { - if( !(obj instanceof LuanFunction) ) - throw new LuanException("bad 'finally' value (function expected, got "+Luan.type(obj)+")"); - finallyFn = (LuanFunction)obj; - } - try { - return tryFn.call(args); - } catch(LuanException e) { - if( catchFn == null ) - throw e; - return catchFn.call(e.table(blocks.luan())); - } finally { - if( finallyFn != null ) - finallyFn.call(); - } - } - - public static Object[] pcall(LuanFunction f,Object... args) { - try { - Object[] r = Luan.array(f.call(args)); - Object[] rtn = new Object[r.length+1]; - rtn[0] = true; - for( int i=0; i<r.length; i++ ) { - rtn[i+1] = r[i]; - } - return rtn; - } catch(LuanException e) { - return new Object[]{false,e.table(f.luan())}; - } - } - public static String number_type(Number v) throws LuanException { Utils.checkNotNull(v); return v.getClass().getSimpleName().toLowerCase();
--- a/src/luan/modules/Boot.luan Fri Jun 19 20:10:47 2020 -0600 +++ b/src/luan/modules/Boot.luan Sun Jun 21 18:14:13 2020 -0600 @@ -5,7 +5,6 @@ local new_error = BasicLuan.new_error local ipairs = BasicLuan.ipairs local set_metatable = BasicLuan.set_metatable -local try = BasicLuan.try_ local load = BasicLuan.load local type = BasicLuan.type local StringLuan = require "java:luan.modules.StringLuan" @@ -29,12 +28,11 @@ LuanJava.checkCallerSecurity("no_security") return function(...) local security = LuanJava.setSecurity(nil) - return try( { - fn - finally = function() - security and LuanJava.setSecurity(security) - end - }, ... ) + try + return fn(...) + finally + security and LuanJava.setSecurity(security) + end end end Boot.no_security = no_security
--- a/src/luan/modules/Io.luan Fri Jun 19 20:10:47 2020 -0600 +++ b/src/luan/modules/Io.luan Sun Jun 21 18:14:13 2020 -0600 @@ -23,7 +23,6 @@ local error = Luan.error local to_string = Luan.to_string or error() local type = Luan.type or error() -local try = Luan.try or error() local ipairs = Luan.ipairs or error() local pairs = Luan.pairs or error() local values = Luan.values or error() @@ -63,15 +62,12 @@ function Io.output_to(out,fn) local old_out = Io.stdout - return try { - function() - Io.stdout = out - return fn() - end - finally = function() - Io.stdout = old_out - end - } + try + Io.stdout = out + return fn() + finally + Io.stdout = old_out + end end local uri = Io.uri -- make local @@ -94,26 +90,20 @@ end local env = {} for line in console do - try { - function() - local fn - try { - function() - fn = load("return "..line,"stdin",env) - end - catch = function(e) - fn = load(line,"stdin",env) - end - } - local rtn = pack( fn() ) - if rtn.n > 0 then - Io.print( unpack(rtn) ) - end + try + local fn + try + fn = load("return "..line,"stdin",env) + catch e + fn = load(line,"stdin",env) end - catch = function(e) - Io.print(e) + local rtn = pack( fn() ) + if rtn.n > 0 then + Io.print( unpack(rtn) ) end - } + catch e + Io.print(e) + end end end
--- a/src/luan/modules/Luan.luan Fri Jun 19 20:10:47 2020 -0600 +++ b/src/luan/modules/Luan.luan Sun Jun 21 18:14:13 2020 -0600 @@ -16,7 +16,6 @@ Luan.new_error = BasicLuan.new_error Luan.pairs = BasicLuan.pairs Luan.parse = LuanParser.parse -Luan.pcall = BasicLuan.pcall Luan.range = BasicLuan.range Luan.raw_equal = BasicLuan.raw_equal Luan.raw_get = BasicLuan.raw_get @@ -25,7 +24,6 @@ Luan.set_metatable = BasicLuan.set_metatable Luan.stringify = BasicLuan.stringify Luan.to_string = BasicLuan.to_string -Luan.try = BasicLuan.try_ Luan.type = BasicLuan.type Luan.values = BasicLuan.values
--- a/src/luan/modules/Rpc.luan Fri Jun 19 20:10:47 2020 -0600 +++ b/src/luan/modules/Rpc.luan Sun Jun 21 18:14:13 2020 -0600 @@ -15,7 +15,6 @@ local Luan = require "luan:Luan.luan" local error = Luan.error local set_metatable = Luan.set_metatable or error() -local try = Luan.try or error() local ipairs = Luan.ipairs or error() local type = Luan.type or error() local Boot = require "luan:Boot.luan" @@ -112,20 +111,17 @@ client.close() return end - return try { - function() - local result = client.read() - return luan_args(result.returnValues,result["in"]) + try + local result = client.read() + return luan_args(result.returnValues,result["in"]) + catch e + local cause = e.java.getCause() + if cause ~= nil and cause.instanceof(RpcException) and cause.getMessage() == "luan" then + error(cause.values.get(0)) + else + e.throw() end - catch = function(e) - local cause = e.java.getCause() - if cause ~= nil and cause.instanceof(RpcException) and cause.getMessage() == "luan" then - error(cause.values.get(0)) - else - e.throw() - end - end - } + end end_function end_function @@ -152,18 +148,15 @@ server.write(JavaRpc.COMMAND_NOT_FOUND) return end_if - local rtn = try { - function() - return {fn(luan_args(call.args,call["in"]))} - end - catch = function(e) - logger.warn(e) - local ex = RpcException.new("luan",e.get_message()) - server.write(ex) - return nil - end - } - if rtn==nil then return end + local rtn + try + rtn = {fn(luan_args(call.args,call["in"]))} + catch e + logger.warn(e) + local ex = RpcException.new("luan",e.get_message()) + server.write(ex) + return + end local binary_in, len_in = encode_binary(rtn) local result if binary_in == nil then @@ -211,32 +204,25 @@ socket_server.setEnabledCipherSuites(Rpc.cipher_suites) end while true do - try { - function() - local socket = socket_server.accept() - local function server() - local responder = nil - try { - function() - responder = rpc_responder(socket,fns) - while not responder.is_closed() do - responder.respond() - end - end - catch = function(e) - logger.warn(e) - end - finally = function() - responder and responder.after_close and responder.after_close() - end - } + try + local socket = socket_server.accept() + local function server() + local responder = nil + try + responder = rpc_responder(socket,fns) + while not responder.is_closed() do + responder.respond() + end + catch e + logger.warn(e) + finally + responder and responder.after_close and responder.after_close() end - Thread.fork(server) end - catch = function(e) - logger.error(e) - end - } + Thread.fork(server) + catch e + logger.error(e) + end end_while end_function
--- a/src/luan/modules/Thread.luan Fri Jun 19 20:10:47 2020 -0600 +++ b/src/luan/modules/Thread.luan Sun Jun 21 18:14:13 2020 -0600 @@ -4,7 +4,6 @@ local Luan = require "luan:Luan.luan" local error = Luan.error local set_metatable = Luan.set_metatable or error() -local try = Luan.try or error() local Time = require "luan:Time.luan" local Logging = require "luan:logging/Logging.luan" local logger = Logging.logger "Thread" @@ -16,12 +15,11 @@ local function safe(fn) return function() - try { - fn - catch = function(e) - logger.error(e) - end - } + try + fn() + catch e + logger.error(e) + end end end
--- a/src/luan/modules/http/Http_test.luan Fri Jun 19 20:10:47 2020 -0600 +++ b/src/luan/modules/http/Http_test.luan Sun Jun 21 18:14:13 2020 -0600 @@ -1,7 +1,6 @@ local Luan = require "luan:Luan.luan" local error = Luan.error local set_metatable = Luan.set_metatable or error() -local try = Luan.try or error() local Package = require "luan:Package.luan" local Io = require "luan:Io.luan" local String = require "luan:String.luan" @@ -20,30 +19,24 @@ path = path .. Http_test.welcome_file end local old_out = Io.stdout - try { - function() - local mod = Package.load("site:"..path..".luan") or error(path.." not found") - mod() - Http_test.text_writer.close() - end - finally = function() - Io.stdout = old_out - end - } + try + local mod = Package.load("site:"..path..".luan") or error(path.." not found") + mod() + Http_test.text_writer.close() + finally + Io.stdout = old_out + end return Http_test.result.read_text() end function Http_test.run_page(page_fn) local old_out = Io.stdout - try { - function() - page_fn() - Http_test.text_writer.close() - end - finally = function() - Io.stdout = old_out - end - } + try + page_fn() + Http_test.text_writer.close() + finally + Io.stdout = old_out + end return Http_test.result.read_text() end
--- a/src/luan/modules/http/Server.luan Fri Jun 19 20:10:47 2020 -0600 +++ b/src/luan/modules/http/Server.luan Sun Jun 21 18:14:13 2020 -0600 @@ -4,7 +4,6 @@ local gsub = String.gsub or error() local match = String.match or error() local matches = String.matches or error() -local try = Luan.try or error() local Io = require "luan:Io.luan" local uri = Io.uri or error() local Package = require "luan:Package.luan" @@ -45,16 +44,13 @@ end function Server.start(server) - try { - function() - LuanHandler.start(server) - end - catch = function(e) --- e.java.printStackTrace(); - Io.print_to(Io.stderr, e ) - System.exit(-1) - end - } + try + LuanHandler.start(server) + catch e +-- e.java.printStackTrace(); + Io.print_to(Io.stderr, e ) + System.exit(-1) + end end function Server.start_rpc(luan_handler)
--- a/src/luan/modules/http/tools/Run.luan Fri Jun 19 20:10:47 2020 -0600 +++ b/src/luan/modules/http/tools/Run.luan Sun Jun 21 18:14:13 2020 -0600 @@ -1,7 +1,6 @@ local Luan = require "luan:Luan.luan" local error = Luan.error local load = Luan.load or error() -local try = Luan.try or error() local Io = require "luan:Io.luan" local print = Io.print or error() local String = require "luan:String.luan" @@ -68,23 +67,20 @@ <% end function Run.run(code,source_name) - return try { - function() - local run = load(code,source_name) - run() - return true - end - catch = function(e) - Http.response.reset() - Http.response.headers["content-type"] = "text/plain; charset=utf-8" - Io.stdout = Http.response.text_writer() - print(e) - print() - print() - print_with_line_numbers(code) - return false - end - } + try + local run = load(code,source_name) + run() + return true + catch e + Http.response.reset() + Http.response.headers["content-type"] = "text/plain; charset=utf-8" + Io.stdout = Http.response.text_writer() + print(e) + print() + print() + print_with_line_numbers(code) + return false + end end function Run.respond()
--- a/src/luan/modules/http/tools/Shell.luan Fri Jun 19 20:10:47 2020 -0600 +++ b/src/luan/modules/http/tools/Shell.luan Sun Jun 21 18:14:13 2020 -0600 @@ -2,7 +2,6 @@ local error = Luan.error local load = Luan.load or error() local to_string = Luan.to_string or error() -local try = Luan.try or error() local range = Luan.range or error() local Table = require "luan:Table.luan" local concat = Table.concat or error() @@ -33,24 +32,16 @@ local fns = {} function fns.run(cmd) - return try { - function() - local line - try { - function() - line = load("return "..cmd,"<web_shell>",env) - end - catch = function(e) - line = load(cmd,"<web_shell>",env) - end - } - return line() + try + try + return load("return "..cmd,"<web_shell>",env) + catch e + return load(cmd,"<web_shell>",env) end - catch = function(e) --- Io.print_to(Io.stderr,e) - return to_string(e) - end - } + catch e +-- Io.print_to(Io.stderr,e) + return to_string(e) + end end local timeout = Time.period{hours=10}
--- a/website/src/diff.html Fri Jun 19 20:10:47 2020 -0600 +++ b/website/src/diff.html Sun Jun 21 18:14:13 2020 -0600 @@ -45,6 +45,7 @@ <ul> <li><a href="#control">Control Structures</a></li> <li><a href="#for">For Statement</a></li> + <li><a href="#try">Try Statement</a></li> <li><a href="#logical">Logical Statements</a></li> <li><a href="#template_stmt">Template Statements</a></li> </ul> @@ -95,7 +96,7 @@ <h3 heading><a name="error" href="#error">Error Handling</a></h3> -<p>Luan has the functions <code>error</code> and <code>pcall</code> but does not have <code>xpcall</code>. Luan adds the function <code>try</code> which looks and acts like try-catch blocks in other languages. Luan errors are implemented as an error table, not as a message object.</p> +<p>Luan has the functions <code>error</code> but does not have <code>pcall</code> or <code>xpcall</code>. Luan adds the <a href="#try">try statement</a> instead. Luan errors are implemented as an error table, not as a message object.</p> <h3 heading><a name="meta" href="#meta">Metatables and Metamethods</a></h3> @@ -165,6 +166,11 @@ end </pre> + +<h4 heading><a name="try" href="#for">Try Statement</a></h4> + +<p>Unlike Lua, Luan has a <b>try</b> statement. See <a href="manual.html#try">Try Statement</a> in the Luan Reference Manual. This also eliminates the need for Lua's <b>pcall</b> function which Luan doesn't have.</p> + <h4 heading><a name="logical" href="#logical">Logical Statements</a></h4> <p>Unlike Lua, Luan allows <b>or</b> and <b>and</b> expressions to be stand-alone statements. This is useful in cases like this:</p>
--- a/website/src/manual.html Fri Jun 19 20:10:47 2020 -0600 +++ b/website/src/manual.html Sun Jun 21 18:14:13 2020 -0600 @@ -52,6 +52,7 @@ <li><a href="#assignment">Assignment</a></li> <li><a href="#control">Control Structures</a></li> <li><a href="#for">For Statement</a></li> + <li><a href="#try">Try Statement</a></li> <li><a href="#fn_stmt">Function Calls as Statements</a></li> <li><a href="#local_stmt">Local Declarations</a></li> <li><a href="#template_stmt">Template Statements</a></li> @@ -243,8 +244,7 @@ Luan code can explicitly generate an error by calling the <a href="#Luan.error"><code>error</code></a> function. If you need to catch errors in Luan, -you can use <a href="#Luan.pcall"><code>pcall</code></a> or <a href="#Luan.try"><code>try</code></a> -to call a given function in <em>protected mode</em>. +you can use the <a href="#try">Try Statement</code></a>. <p> @@ -1041,6 +1041,17 @@ +<h4 heading><a name="try" href="#for">Try Statement</a></h4> + +<p>The <b>try</b> statement has the same semantics as in Java.</p> + +<pre> + stat ::= <b>try</b> block [<b>catch</b> Name block] [<b>finally</b> block] end_try + end_try ::= <b>end_try</b> | <b>end</b> +</pre> + + + <h4 heading><a name="fn_stmt" href="#fn_stmt">Function Calls as Statements</a></h4> @@ -1940,23 +1951,6 @@ -<h4 heading><a name="Luan.pcall" href="#Luan.pcall"><code>Luan.pcall (f [, arg1, ···])</code></a></h4> - -<p> -Calls function <code>f</code> with -the given arguments in <em>protected mode</em>. -This means that any error inside <code>f</code> is not propagated; -instead, <code>pcall</code> catches the error -and returns a status code. -Its first result is the status code (a boolean), -which is true if the call succeeds without errors. -In such case, <code>pcall</code> also returns all results from the call, -after this first result. -In case of any error, <code>pcall</code> returns <b>false</b> plus the error. - - - - <p> <hr><h3><a name="pdf-print"><code>print (···)</code></a></h3> Receives any number of arguments @@ -2076,48 +2070,6 @@ -<h4 heading><a name="Luan.try" href="#Luan.try"><code>Luan.try (t, ···)</code></a></h4> - -<p> -Implements try-catch as found in other languages where each block is in table <code>t</code>. <code>t[1]</code> is the "try" block. The <code>t.catch</code> and <code>t.finally</code> blocks are optional. Any extra arguments are passed to the "try" function. Returns the result of the "try" block or the "catch" block. - -<p> -Example use: - -<pre> -try { - function() - a_dangerous_fn() - end - catch = function(e) - -- handle error - end - finally = function() - -- clean up - end -} -</pre> - -<p> -Could be defined as: - -<pre> - function Luan.try(t) - local r = { <a href="#Luan.pcall">Luan.pcall</a>(t[1]) } - if r[1] then - Table.remove(r,1) - elseif t.catch ~= nil then - r = { t.catch(r[2]) } - else - t.finally and t.finally() - r[2].throw() - end - t.finally and t.finally() - return Table.unpack(r) - end -</pre> - - <h4 heading><a name="Luan.type" href="#Luan.type"><code>Luan.type (v)</code></a></h4> <p>