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
diff -r 3ebf9781707c -r d9a5405a3102 conv.txt
--- 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
 
diff -r 3ebf9781707c -r d9a5405a3102 src/luan/cmd_line.luan
--- 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
diff -r 3ebf9781707c -r d9a5405a3102 src/luan/host/main.luan
--- 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"
diff -r 3ebf9781707c -r d9a5405a3102 src/luan/impl/LuanImpl.java
--- 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 {}
+
 }
diff -r 3ebf9781707c -r d9a5405a3102 src/luan/impl/LuanParser.java
--- 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",
diff -r 3ebf9781707c -r d9a5405a3102 src/luan/modules/BasicLuan.java
--- 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();
diff -r 3ebf9781707c -r d9a5405a3102 src/luan/modules/Boot.luan
--- 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
diff -r 3ebf9781707c -r d9a5405a3102 src/luan/modules/Io.luan
--- 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
 
diff -r 3ebf9781707c -r d9a5405a3102 src/luan/modules/Luan.luan
--- 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
 
diff -r 3ebf9781707c -r d9a5405a3102 src/luan/modules/Rpc.luan
--- 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
 
diff -r 3ebf9781707c -r d9a5405a3102 src/luan/modules/Thread.luan
--- 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
 
diff -r 3ebf9781707c -r d9a5405a3102 src/luan/modules/http/Http_test.luan
--- 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
 
diff -r 3ebf9781707c -r d9a5405a3102 src/luan/modules/http/Server.luan
--- 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)
diff -r 3ebf9781707c -r d9a5405a3102 src/luan/modules/http/tools/Run.luan
--- 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()
diff -r 3ebf9781707c -r d9a5405a3102 src/luan/modules/http/tools/Shell.luan
--- 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}
diff -r 3ebf9781707c -r d9a5405a3102 website/src/diff.html
--- 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>
diff -r 3ebf9781707c -r d9a5405a3102 website/src/manual.html
--- 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, &middot;&middot;&middot;])</code></a></h4>
-
-<p>
-Calls function <code>f</code> with
-the given arguments in <em>protected mode</em>.
-This means that any error inside&nbsp;<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 (&middot;&middot;&middot;)</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, &middot;&middot;&middot;)</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>