Lua run time error occurred

Есть какая-нибудь возможность кидать хотя бы е-мейлы через скрипт?

Кто как решил вопрос уведомления о сделках?

Главная » Основные форумы » Программирование на языке Lua

Страницы:
Пред.
1
2
3

 

Анатолий


Пользователь

Сообщений: 128
Регистрация: 09.10.2018

#101

24.02.2019 19:23:47

Цитата
SDL написал:
Цитата s_mike@rambler.ru  пишет: Серверов, не нуждающихся, например, в TLS/SSL, уже мало и количество их уменьшается. Обычно это древние сервера. Дописывать библиотеку для поддержки новых стандартов, как я понимаю, никто не собирается.Главное не отчаиваться и слишком быстро не сдаваться.Качаем модуль LuaSec:Проект:  https://github.com/brunoos/luasec Бинарники можно взять тут:  http://love2d.org/forums/viewtopic.php?f=5&t=76728 . Нужны 2 файла — ssl.dll и ssl.lua.Использует библиотеки OpenSSL libeay32.dll и ssleay32.dll. Скачать, если нет, и не забыть обеспечить к ним доступ — через окружение (PATH) или можно кинуть в папку с QUIK.Подключаем:
Код
package.path = …
package.cpath = …
ssl = require «ssl»
Добавляем вот такую функцию:
Код
function sslCreate()
  local conn =
  {
     sock = socket.tcp(),
     connect = function(self, host, port)
        local r, e = self.sock:connect(host, port)
        if not r then return r, e end
        self.sock = ssl.wrap(self.sock, {mode = ‘client’, protocol = ‘tlsv1’})
        return self.sock:dohandshake()
     end
  }

  local fnIdx = function(t, key)
     return function(self, …)
        return self.sock[key](self.sock, …)
     end
  end

  return setmetatable(conn, {__index = fnIdx})
end
… и отправляем:Кодsocket.smtp.send
{
  from = …,
  rcpt = …,
  source = …,
  server = «smtp.mail.ru»,
  port = 465,
  user = «user»,
  password = «password»,
  create = sslCreate
}И еще вкратце, что это за безобразие такое. Вся соль в возможности smtp.send() luasocket’а (см. доки) задать свою функцию создания сокета для отправки сообщения (create = sslCreate), который по умолчанию делается библиотекой просто как socket.tcp(). Мы делаем то же самое, но только обертываем его в подмененном методе connect, где нужно «договориться» с сервером по протоколу SSL. Всё. Еще в этой функции код для доступа к остальным методам сокета, ведь далее luasocket будет работать с ним как со стандартным.С mail.ru, например, работает без проблем.

Здравствуйте, взял все что необходимо для работы с сокетами SMTP и SSL из ZerobraneStudio и закинул в QUIK, закинул все нужные библиотеки core.dll socket.lua smtp.lua ssl.dll ssl.lua по нужным местам, скопировал ssleay32.dll и libeay32.sdll, скопировал Qlua.dll в lua51.dll, сделал все по рецепту автора, при выполнении скрипт в QUIKе отваливается с сообщением » Lua run time error occurred.»,  провел отладку выполнения скрипта через Decoda — результат такой мой скрипт выполняется нормально, потом доходит до отправки емейла — тут тоже все нормально, доходит до строчки create = sslCreate дальше переходит в функцию function sslCreate() дальше при идет нормально и в один из моментов когда в файле ssl.lua доходит до строчки № 134  registry[s] = ctx весь скрипт в QUIKе  тваливается с вот этой вот ошибкой » Lua run time error occurred.»

ssl.lua  строчка 134 registry[s] = ctx

Код
local function wrap(sock, cfg)
   local ctx, msg
   if type(cfg) == "table" then
      ctx, msg = newcontext(cfg)
      if not ctx then return nil, msg end
   else
      ctx = cfg
   end
   local s, msg = core.create(ctx)
   if s then
      core.setfd(s, sock:getfd())
      sock:setfd(-1)
      registry[s] = ctx
      return s
   end
   return nil, msg 
end

При том что проверил в ZerobraneStudio мой кусок кода отправляющий емейл и функция автора sslCreate() работают нормально — емейл отправляется без проблем, у кого будут какие соображения в чем проблема?

 

Анатолий


Пользователь

Сообщений: 128
Регистрация: 09.10.2018

#102

24.02.2019 19:43:19

В момент выполнения строки registry[s] = ctx:   ctx= SSL context: 0D72EE88    тип — userdata   s = SSL connection: 0D848F00  тип — userdata
sock = tcp{client}:0D846E88    setfd=nil
Вообщем мне кажется что это связано с квиковским интерпретатором луа, т.к. операция registry это сохранение любых значений C кода в специальной общей таблице для всех выполняемых С кодов, вот тут в чем о и проблема, т.к. в других интерпретаторах, том же Zerobrane, такой проблемы нет

 

Nikolay


Пользователь

Сообщений: 698
Регистрация: 27.01.2017

#103

28.05.2019 17:57:11

Добрый день.

Я подключил все библиотеки, socket подключается нормально. Но при подключении ssl, не находит ssl.core. ssl.lua, собственно, и пытается его включить local core    = require(«ssl.core»)
Т.е. нужна папка ssl а в ней файл core.dll

Попробовал взять сборку Телеграм бота, что здесь выкладывали, аналогичная проблема. Похоже какая-то библиотека все же отсутствует.
Кто-то встречал похожую ошибку? Я нашел упоминания, то это связано с libeay32 и ssleay32, но они есть, путь к ним прописан. Плюс пробовал класть их в разные папки.

https://nick-nh.github.io/
https://github.com/nick-nh/qlua

 

Nikolay


Пользователь

Сообщений: 698
Регистрация: 27.01.2017

#104

28.05.2019 20:19:50

А тоже самое из ZeroBraneStudio работает. ssl.core — ошибку не дает, письма отправляются. А Квик ошибку выдает на local core    = require(«ssl.core») в  ssl.lua

https://nick-nh.github.io/
https://github.com/nick-nh/qlua

 

Анатолий


Пользователь

Сообщений: 128
Регистрация: 09.10.2018

#105

29.05.2019 12:38:15

Цитата
Nikolay написал:
Я подключил все библиотеки, socket подключается нормально. Но при подключении ssl, не находит ssl.core. ssl.lua, собственно, и пытается его включить local core    = require(«ssl.core»)Т.е. нужна папка ssl а в ней файл core.dll

Скопируй из квика из окна «Ошибки выполнения скрипта» то что там пишется при твоей попытке выполнить скрипт и выложи это сюда»

 

Nikolay


Пользователь

Сообщений: 698
Регистрация: 27.01.2017

#106

30.05.2019 13:02:52

Цитата
Анатолий написал:

Цитата
Nikolay написал:
Я подключил все библиотеки, socket подключается нормально. Но при подключении ssl, не находит ssl.core. ssl.lua, собственно, и пытается его включить local core    = require(«ssl.core»)Т.е. нужна папка ssl а в ней файл core.dll

Скопируй из квика из окна «Ошибки выполнения скрипта» то что там пишется при твоей попытке выполнить скрипт и выложи это сюда»

Ну так и пишется, что не может загрузить модуль. Все пути прописаны, библиотека рабочая, взята из поставки ZeroBraneStudio. Из нее все прекрасно работает. При этом просто socket загружается нормально.

Код
error loading module 'ssl.core' from file 'ssl.dll':
   Не найден указанный модуль.

https://nick-nh.github.io/
https://github.com/nick-nh/qlua

 

Nikolay


Пользователь

Сообщений: 698
Регистрация: 27.01.2017

#107

30.05.2019 13:09:56

Цитата
Анатолий написал:
В момент выполнения строки registry = ctx:   ctx= SSL context: 0D72EE88    тип — userdata   s = SSL connection: 0D848F00  тип — userdatasock = tcp{client}:0D846E88    setfd=nilВообщем мне кажется что это связано с квиковским интерпретатором луа, т.к. операция registry это сохранение любых значений C кода в специальной общей таблице для всех выполняемых С кодов, вот тут в чем о и проблема, т.к. в других интерпретаторах, том же Zerobrane, такой проблемы нет

Я тоже подозреваю, что с интерпретатором lua в Квике не все ладно. У меня также из ZeroBraneStudio все работает.
Также не все библиотеки можно подключить в Квике, для примера strict —  Квик падает без слов.
Также обнаружил, что внутри фунции SearchItems (в функции проверки) у меня почему-то проверка nil как false не срабатывает. Приходится явно писать ~= nil

https://nick-nh.github.io/
https://github.com/nick-nh/qlua

 

Анатолий


Пользователь

Сообщений: 128
Регистрация: 09.10.2018

#108

30.05.2019 15:31:23

Цитата
Nikolay написал:
Я тоже подозреваю, что с интерпретатором lua в Квике не все ладно. У меня также из ZeroBraneStudio все работает.

С интерпретатором луа в квике все ладно, просто там есть нюансы, у меня были все эти проблемы и я их решил, помоему ты всетаки не все скопировал из окна ошибок, полностью все оттуда скопируй и вставь сюда, или лучше сделай скрин и выложи

 

Nikolay


Пользователь

Сообщений: 698
Регистрация: 27.01.2017

#109

30.05.2019 15:37:51

Цитата
Анатолий написал:

Цитата
Nikolay написал:
Я тоже подозреваю, что с интерпретатором lua в Квике не все ладно. У меня также из ZeroBraneStudio все работает.

С интерпретатором луа в квике все ладно, просто там есть нюансы, у меня были все эти проблемы и я их решил, помоему ты всетаки не все скопировал из окна ошибок, полностью все оттуда скопируй и вставь сюда, или лучше сделай скрин и выложи

Я скопировал все, кроме полного пути до файла ssl.dll. Больше ошибок нет. Выше по сообщениям этой темы были аналогичные сообщения.Если бы интерпретатор луа был чист, то типовая библиотека strict не приводила бы к падению терминала.

https://nick-nh.github.io/
https://github.com/nick-nh/qlua

 

Анатолий


Пользователь

Сообщений: 128
Регистрация: 09.10.2018

#110

30.05.2019 19:43:59

Сложно так сказать не видя что у тебя в скрипте и в папках квика, покажи тогда свой кусок скрипта где обьявляются пути

package.cpath  = …
package.path  = …

и идет подключение библиотек командой require

 

Nikolay


Пользователь

Сообщений: 698
Регистрация: 27.01.2017

#111

30.05.2019 20:12:12

Цитата
Анатолий написал:
Сложно так сказать не видя что у тебя в скрипте и в папках квика, покажи тогда свой кусок скрипта где обьявляются пути

package.cpath  = …
package.path  = …

и идет подключение библиотек командой require

Так а что здесь такого при подключении… Я же говорю, что этот же скрипт ZeroBraneStudio в работает.
Отличие в том, что у него свои пути к библиотекам. А здесь такие.
Попытка поставить пути из ZeroBraneStudio для Квика приводит к аналогичной ошибке.

gSPath = ‘D:\Projects\qlua_work’
gPath  = ‘C:\QUIK-Junior’
package.cpath = gPath..»\?.dll;»..gSPath ..»\lua_socket_ssl\?.dll;» ..gSPath ..»\lua_socket_ssl\clibs\?.dll;» ..gSPath ..»\lua_socket_ssl\clibs\mime\?.dll;» ..gSPath ..»\lua_socket_ssl\clibs\socket\?.dll;» .. package.cpath
package.path  = gSPath ..»\lua_socket_ssl\?.lua;»..gSPath ..»\lua_socket_ssl\socket\?.lua;»..gSPath ..»\lua_socket_ssl\ssl\?.lua;» ..package.path

print(package.cpath)
print(package.path)

socket  = require(«socket»)
smtp    = require(«socket.smtp»)
ssl     = require(«ssl») — вот здесь и падает в Квике

https://nick-nh.github.io/
https://github.com/nick-nh/qlua

 

Анатолий


Пользователь

Сообщений: 128
Регистрация: 09.10.2018

#112

30.05.2019 21:12:40

Цитата
Nikolay написал:
socket  = require(«socket»)

А у меня такой строчки нету и все работает, короче у меня все прописано вот так:
package.cpath  =  getScriptPath () .. «\ssl\?.dll;C:\ZeroBraneStudio\bin\clibs\?.dll;C:\ZeroBraneStudio\bin\?.dll;C:\ZeroBraneStudio\bin\socket\?.dll»
package.path  =   getScriptPath () .. «\?.lua;»..package.path

smtp = require(«socket.smtp»)
mime = require(«mime»)
ltn12 = require(«ltn12»)
ssl = require(«ssl»)
https = require(«ssl.https»)

В папке квика — папка lua, в ней папки socket и ssl в них я закинул dll’ки, ssl.lua в самой папке lua, надо подумать какой прогой можно сделать чтобы сделать удобный листинг папок и закинуть их сюда,
Но есть еще один удобный выход который я и предпочел т.к. у меня либа ssl хоть и подключилась и работает однако она доставляет неудобства — с ней скрипт очень долго стартует — минут 5 наверно, почему непонятно, поэтому я от неё отказался и воспользовался прогой Stunnel, ищи в инете, она создает прокси SSL туннель и переправляет направляемый на неё траффик по ssl, и тогда в скрипте

ты отправляешь через неё мыло вот так:

function sendmail (message)
local r,e

r, e = smtp.send{
 from = «

somemail@mail.ru

«,
 rcpt = «

recepient@mail.ru

«,
 source = smtp.message(message),
 password = «password»,
 user = «

somemail

«,
 domain = «mail.ru»,
 server = «127.0.0.1»,
 port = 25,
}

return r,e

end

а в настройках Stunnel указываешь:

[mail-pop3]
client = yes
accept = 127.0.0.1:110
connect = pop.mail.ru:995
verifyChain = yes
CAfile = ca-certs.pem
checkHost = pop.gmail.com
OCSPaia = yes

[mail-smtp]
client = yes
accept = 127.0.0.1:25
connect = smtp.mail.ru:465
verifyChain = yes
CAfile = ca-certs.pem
checkHost = smtp.mail.ru
OCSPaia = yes

Все просто и понятно
И тогда твое мыло и без подключения ssl.dll уйдет на почту на порт 465 по SSL

 

Nikolay


Пользователь

Сообщений: 698
Регистрация: 27.01.2017

#113

30.05.2019 21:26:17

Цитата
Анатолий написал:

Цитата
Nikolay написал:
socket  = require(«socket»)

А у меня такой строчки нету и все работает, короче у меня все прописано вот так:

Ну я хочу использовать эту библиотеку не для отправки почты. Для почты я написал на C# програмульку на 10 строк, вызываю ее из Квика и все.
А вот для других целей хочется запустить. Ясно, что дело в путях, т.к. в другом месте работает. Будем копать…

https://nick-nh.github.io/
https://github.com/nick-nh/qlua

 

Nikolay


Пользователь

Сообщений: 698
Регистрация: 27.01.2017

#114

06.06.2019 12:25:32

Проблему решил.
Пришлось скомпилировать самому luaSec 0.8-1 под lua 5.1, используя Open SSL.
Файлы libeay32 и ssleay32 обязаны быть рядом с файлом lua 5.1, т.е. в папке установки Quik.

У меня отправка почты совершается за секунду, две. Не более. Никаких задержек.

Теперь можно приступать к использованию библиотеки для интересных вещей, типа чтения Twitter и т.д.

Если кому интересно, готовая сборка с примером отправки почты с моего Гита:

https://github.com/nick-nh/qlua/tree/master/lua_socket_ssl

https://nick-nh.github.io/
https://github.com/nick-nh/qlua

 

Анатолий


Пользователь

Сообщений: 128
Регистрация: 09.10.2018

#115

16.06.2019 09:50:22

Цитата
Nikolay написал:
Я тоже подозреваю, что с интерпретатором lua в Квике не все ладно. У меня также из ZeroBraneStudio все работает. Также не все библиотеки можно подключить в Квике, для примера strict —  Квик падает без слов. Также обнаружил, что внутри фунции SearchItems (в функции проверки) у меня почему-то проверка nil как false не срабатывает. Приходится явно писать ~= nil

Кстати забыл сразу рассказать: у меня тоже по началу были такие проблемы с квиковским интерпретатором луа, но они решились все и больше не появлялись, а вызваны как мне кажется следующим — ты как и все остальные делаете так:
В папку со сторонними библиотеками ложите файл qlua.dll переименовав его в lua51.dll, еще хуже если люди берут lua51.dll откуда нибудь со стороны, из Zerobrane например, не переименовав оригинальный qlua.dll, тогда всякие глюки 100% будут, но и в первом случае — с помощью переименовывания qlua.dll  в lua51.dll я тоже наблюдал различные глюки и сообщения о некоторых ошибках во время выполнения скрипта, все эти ошибки у меня решились так:
1. В каждую папку со сторонними библиотеками ложится оригинальный qlua.dll а всякие lua51.dll удаляются.
2. Есть такая хорошая программка Dependency walker, с её помощь можно посмотреть с какими другими dll связана нужная тебе dll библиотека, но еще удобнее это посмотреть с помощью Total Commander Extended — просто становишся на dll’ку курсором, жамкаешь F3, вкладка Dll Dependency — смотрим — эта библиотека, к примеру ssl.dll требует для своей работы библиотеку lua51.dll, и кстати там будет показано — может ли нужная тебе библиотека связаться со всеми далее необходимыми ей библиотеками, если нет то возле нее будет гореть красный крестик
3. Далее любым HEX редактором, например WinHex, открываем ssl.dll для записи, ищем текст — lua51.dll
находим, далее осторожно! Необходимо стать курсором в текстовое поле отображения файла! не в шестнадцатиричное!  необходимо написать qlua вместо lua51, но при этом существующее положение точки т.е. символа разделения имени файла и расширения не должно измениться, т.е. точку трогать нельзя! qlua это на один символ меньше чем lua51, поэтому «q» писываем вместо «u» и т.д. итого у нас должно получится — lqlua.dll,  после того как писали qlua осторожно переходим в шестнадцатиричное поле и в ту позицию (байт) в которой содержится шестнадцатиричное значение буквы l ставим два нуля — «00» и буква l должна исчезнуть, сохраняем все изменения, открываем ssl.dll в Total’е, или в Dependency walker, смотрим — ssl.dll уже запрашивает не библиотеку lua51.dll а qlua.dll! Так проделываем со всеми своими сторонними библиотеками подключаемыми в скрипте самостоятельно — после этого у меня все проблемы с интерпретатором луа в квике пропали!

 

SDL


Пользователь

Сообщений: 125
Регистрация: 29.04.2015

#116

16.06.2019 14:30:37

Цитата
Анатолий написал:

Далее любым HEX редактором …

Есть более гуманный способ. Вот небольшой технологический дайджест по теме:

1. qlua.dll — реализация lua5.1.dll специально для Квика с целью добавления потокобезопасных методов работы с таблицами из разных потоков (sinsert(), sremove() и т.п. — см. документацию по QLua). В остальном это полноценная Lua, с которой можно линковать и свои модули.
2. Чтобы всё работало, процесс вне зависимости от числа созданных в нем потоков должен загрузить только один экземпляр qlua.dll. Почему? В DLL помимо кода (количество экземпляров которого безразлично) есть еще и глобальные переменные, в числе которых необходимые примитивы синхронизации. Если они будут созданы в нескольких экземплярах, толку от них никакого и все труды по обеспечению потокобезопасности — впустую.
3. Так как сторонние библиотеки едва что-нибудь слыхивали про Квик про QLua в нем, то слинкованы они с  lua5.1.dll или нечто подобным. Чтобы такие модули работали со скриптами в Квике, в комплекте программы поставляется  lua5.1.dll — модуль-прокси, который полезного кода не содержит, но перенаправляет все вызовы API к qlua.dll, таким образом решая две задачи: 1) внешние модули, слинкованные с   lua5.1.dll, успешно его находят и загружают; 2) обеспечивается загрузка только одного экземпляра API  Lua, а именно qlua.dll.

Выводы, для того чтобы всё находилось, загружалось и не падал терминал:
1. Из папок с файлами сторонних модулей можно удалить все  lua5.1.dll, чтобы гарантированно обеспечить загрузку   lua5.1.dll именно из папки Квика, то есть нашу заботливо изготовленную прокси.
2. Если внешние модули слинкованы не с lua5.1.dll, а с  lua51.dll,  lua.dll или подобным, скопируйте прокси lua5.1.dll из поставки Квика (!) в ту же его папку и обзовите файл как надо. Внимание, еще раз: qlua.dll копировать нельзя, прокси   lua5.1.dll — можно! А еще лучше не копировать, а создать символическую ссылку (symlink) на lua5.1.dll, если у вас файловая система NTFS. Это избавит от лишних хлопот, если внезапно  lua5.1.dll обновится вместе в Квиком.
3. Кто использует LuaSSL, библиотеки libeay32.dll и ssleay32.dll кладите в папку Квика, так как LuaSSL сделан так, чтобы эти библиотеки и lua5.1.dll находились в одном месте.

 

Nikolay


Пользователь

Сообщений: 698
Регистрация: 27.01.2017

#117

17.06.2019 15:14:17

Как я выше написал, я решил проблему просто — сам скомпилировал библиотеки. И все заработало. Никаких переименований библиотек я не делал.

https://nick-nh.github.io/
https://github.com/nick-nh/qlua

 

alexeyseikin


Пользователь

Сообщений: 1
Регистрация: 28.11.2019

#118

28.11.2019 23:18:41

Кто  нибудь смог запустить этот вариант?

https://quikluacsharp.ru/instruments/otpravka-sms-email-iz-qlua-ili-c/comment-page-4/#comment-28183

 

Александр


Пользователь

Сообщений: 37
Регистрация: 10.10.2017

#119

03.12.2019 13:05:42

alexeyseikin, Где то есть такая же тема тут как делать. Но уже сам автор сделал новый файл для почты. Или речь об смс?

 

Лии


Пользователь

Сообщений: 13
Регистрация: 25.07.2019

#120

26.06.2020 21:46:57

Поделитесь пожалуйста скриптом или подробным описание как делать  отправку оповещения на почту или телеграмм(вроде разблокировали)  с луа квик.  :oops:  

 

Александр


Пользователь

Сообщений: 37
Регистрация: 10.10.2017

#121

26.06.2020 21:51:52

Поддерживаю. Вообще почему в квике нет функции оповещения. Ему значит инет безлимитный, железо все дела. А он отправить даже оповещение не может на почту. В терминалах которые любители пишут и то есть уведомление разные прикручивают.    :cool:  

 

nikolz


Пользователь

Сообщений: 2518
Регистрация: 30.01.2015

#122

27.06.2020 18:51:54

На самом деле посылать письма из квика на смартфон
или оповещать через приложение,  работающие через интернет,
которое установлено  на смартфоне — это какой-то мазохизм.
———————
У вас терминал квика в режиме торгов постоянно включен в интернет
и смартфон тоже в интернете.
Ну так что же вам мешает передать сообщение по схеме pоint to point, а не гонять письма и сообщения через сторонние сервера?
Скорость передачи будет раз в сто выше, а накладные расходы раз в сто меньше.
Делал такое, давно это было.
—————————
Подумайте на досуге.

 

Anton


Пользователь

Сообщений: 1359
Регистрация: 21.08.2015

#123

27.06.2020 19:29:07

Цитата
nikolz написал:
мешает передать сообщение по схеме pоint to point

динамический айпи как минимум с одной стороны, а как правило — с обеих. Если на проводной стороне еще можно купить статический, то на стороне мобилы вряд ли. Времена честных интернетов давно прошли, теперь это телевизор с фидбеком.

 

Nikolay


Пользователь

Сообщений: 698
Регистрация: 27.01.2017

#124

27.06.2020 23:09:42

Цитата
nikolz написал:
На самом деле посылать письма из квика на смартфон
или оповещать через приложение,  работающие через интернет,
которое установлено  на смартфоне — это какой-то мазохизм.
———————
У вас терминал квика в режиме торгов постоянно включен в интернет
и смартфон тоже в интернете.
Ну так что же вам мешает передать сообщение по схеме pоint to point, а не гонять письма и сообщения через сторонние сервера?
Скорость передачи будет раз в сто выше, а накладные расходы раз в сто меньше.
Делал такое, давно это было.
—————————
Подумайте на досуге.

Почта — это один из самых надежных способов доставки сообщений. Плюс реализация ptp обмена — это переусложнение простой задачи. Тем более, что я не хочу держать лишние аппликации типа мессенджеров на устройствах. А почтовый клиент — есть везде, даже на древней нокиа е61.

https://nick-nh.github.io/
https://github.com/nick-nh/qlua

 

Nikolay


Пользователь

Сообщений: 698
Регистрация: 27.01.2017

#125

30.06.2020 09:17:53

Выложил простой пример отправки почты через консольную программу на С#. Я не знаю язык, но он простой, поэтому просто адаптировал пример, найденный в MSDN.

https://github.com/nick-nh/SendEmail

Я предпочитаю именно такой вариант, потому что не надо думать о бинарной совместимости Квика и проблемах библиотек.

https://nick-nh.github.io/
https://github.com/nick-nh/qlua

 

Лии


Пользователь

Сообщений: 13
Регистрация: 25.07.2019

#126

03.07.2020 15:29:11

Nikolay, Спасибо тебе добрый человек. Дай бог здоровья, как моя теща говорит!
Еще бы подробную инструкцию.  :oops: Ну очень тяжело разбираться в чужом коде.
Спасибо. :smile:  

 

Suxov


Пользователь

Сообщений: 26
Регистрация: 28.03.2019

#127

08.09.2020 02:01:34

Цитата
Nikolay написал:
Проблему решил.Пришлось скомпилировать самому luaSec 0.8-1 под lua 5.1, используя Open SSL.Файлы libeay32 и ssleay32 обязаны быть рядом с файлом lua 5.1, т.е. в папке установки Quik.У меня отправка почты совершается за секунду, две. Не более. Никаких задержек.Теперь можно приступать к использованию библиотеки для интересных вещей, типа чтения Twitter и т.д.Если кому интересно, готовая сборка с примером отправки почты с моего Гита: https://github.com/nick-nh/qlua/tree/master/lua_socket_ssl

попробовал как написано просто запустить тест для запроса http
выходит ошибка. я так понимаю нет каких-то еще библиотек.

Код
OAuth.lua:1: module 'base64' not found:
   no field package.preload['base64']

Я пытаюсь сделать простой https запрос, нашел 2 темы которых есть примеры но в итоге не работает нигде. :(

Может кто-то собрал набор для работы с https (просто GET запрос надо отправить и все)?

 

nikolz


Пользователь

Сообщений: 2518
Регистрация: 30.01.2015

#128

08.09.2020 19:56:35

рассказываю еще один простой способ
1) покупаем SIM800L+USBUART adapter  — цена на али 2 доллара
2) берем карточку от любого оператора с самым дешевым тарифом и подключаем к USB.
3) на LUA через UART, с помощью AT команд, можем посылать SMS,  UDP и  TCP пакеты, голосовые сообщения.

 

nikolz


Пользователь

Сообщений: 2518
Регистрация: 30.01.2015

#129

08.09.2020 20:02:47

и самый халявный вариант.
Создаем в облаке ORACLE бесплатный виртуальный сервер и ставим на нем например MQTT брокер.
В итоге можно реализовать обмен информацией по подписке.
Можно и любой другой вариант обмена информацией со своим компом с QUIK

 

Роман


Пользователь

Сообщений: 39
Регистрация: 09.07.2020

#130

24.09.2020 11:11:18

Цитата
Алексей Ч написал:
Перезалил  бота сюда .
В telegram_settings.lua нужно указать настройки бота. В квике запустить telegram.lua
Помимо сообщений о сделках и заявках, сообщает так же по запросам:
Fut — деньги на фортс (вариационная маржа)
Pos — позиции на фортс
Usd — текущие котировки USDRUB_TOM
Eur — соответственно EURRUB_TOM
Если написать код фьюча, то можно получить его котировку.
Любые другие символы сообщают, подключен ли квик или нет. В файл log.txt пишет номер последнего запроса

Добрый день, спасибо за бота, а можете помочь с ошибками?

C:QUIK_VTB_85quik-telegram-bot2socket.lua:13: module ‘socket.core’ not found:

no field package.preload[‘socket.core’]

no file ‘C:QUIK_VTB_85quik-telegram-bot2socketcore.lua’

no file ‘C:Program Files (x86)Lua5.1luasocketcore.lua’

no file ‘C:Program Files (x86)Lua5.1luasocketcoreinit.lua’

no file ‘C:Program Files (x86)Lua5.1socketcore.lua’

no file ‘C:Program Files (x86)Lua5.1socketcoreinit.lua’

no file ‘C:Program Files (x86)Lua5.1luasocketcore.luac’

no file ‘C:Program FilesLua5.1luasocketcore.lua’

no file ‘C:Program FilesLua5.1luasocketcoreinit.lua’

no file ‘C:Program FilesLua5.1socketcore.lua’

no file ‘C:Program FilesLua5.1socketcoreinit.lua’

no file ‘C:Program FilesLua5.1luasocketcore.luac’

no file ‘C:QUIK_VTB_85quik-telegram-bot2socketcore.dll’

no file ‘.socketcore51.dll’

no file ‘C:Program Files

 

Роман


Пользователь

Сообщений: 39
Регистрация: 09.07.2020

#131

25.09.2020 14:41:30

Добрый день. С как эту ошибку исправить?

 

Nikolay


Пользователь

Сообщений: 698
Регистрация: 27.01.2017

#132

08.10.2020 19:03:44

Сделал небольшое решение для отправки сообщений в чат бота телеграма (Telrgram Bot Api).

https://github.com/nick-nh/qlua/tree/master/telegramQuik

Основа — это некое C# консольное приложение (многопоточный сервер), принимающее данные от lua скрипта и отправляющее уже сообщения в чат телеграм. Я предпочитаю делать так, дабы не связываться с проблемами совместимости библиотек lua.

Сначала сделал передачу данных на внутренний сервер через сокеты, но медленно оказалось.
Переделал на Named Pipes, быстрее намного. Пришлось написать библиотеку Named Pipe клиента для lua.

Пока сделал только отправку сообщений, т.к. это самая частая просьба.

https://nick-nh.github.io/
https://github.com/nick-nh/qlua

 

nikolz


Пользователь

Сообщений: 2518
Регистрация: 30.01.2015

#133

10.10.2020 16:42:47

Цитата
Nikolay написал:
Сделал небольшое решение для отправки сообщений в чат бота телеграма (Telrgram Bot Api).
https://github.com/nick-nh/qlua/tree/master/telegramQuik

Основа — это некое C# консольное приложение (многопоточный сервер), принимающее данные от lua скрипта и отправляющее уже сообщения в чат телеграм. Я предпочитаю делать так, дабы не связываться с проблемами совместимости библиотек lua.

Сначала сделал передачу данных на внутренний сервер через сокеты, но медленно оказалось.
Переделал на Named Pipes, быстрее намного. Пришлось написать библиотеку Named Pipe клиента для lua.

Пока сделал только отправку сообщений, т.к. это самая частая просьба.

информация к размышлению.
Вообще-то пакет байтов 500 по UDP сокетами передается даже на луа примерно не более чем за 20 ms. Это медленно?
Какая же у вас получилась скорость ?
—————————  

 

Nikolay


Пользователь

Сообщений: 698
Регистрация: 27.01.2017

#134

10.10.2020 17:00:20

Передача данных быстрая, да. А вот подключение…

Вот чистый lua, библиотека socket, никакого ssl, никакого Квика.

clock 0.007   Attempting connection to host ‘localhost’ and port 8005…
clock 2.06    Connected!
clock 2.06    strin = test
clock 2.06    End

Не было желания постоянно держать открытое соединение.

https://nick-nh.github.io/
https://github.com/nick-nh/qlua

Страницы:
Пред.
1
2
3

Читают тему (гостей: 1)

Содержание

  1. Lua — Error Handling
  2. Complete Python Prime Pack for 2023
  3. Artificial Intelligence & Machine Learning Prime Pack
  4. Java Prime Pack 2023
  5. Need for Error Handling
  6. Syntax Errors
  7. Run Time Errors
  8. Assert and Error Functions
  9. pcall and xpcall
  10. Lua Error Handling
  11. Grammatical errors
  12. Runtime Error
  13. Error Handling
  14. error function
  15. pcall and xpcall, debug
  16. Lua run time error occurred
  17. 8.5 – Error Messages and Tracebacks
  18. Exceptions¶
  19. A runtime error occured: /usr/lib/lua/luci/model/network.lua:187: attempt to index a nil value #2027
  20. Comments

Lua — Error Handling

Complete Python Prime Pack for 2023

9 Courses 2 eBooks

Artificial Intelligence & Machine Learning Prime Pack

6 Courses 1 eBooks

Java Prime Pack 2023

8 Courses 2 eBooks

Need for Error Handling

Error handling is quite critical since real-world operations often require the use of complex operations, which includes file operations, database transactions and web service calls.

In any programming, there is always a requirement for error handling. Errors can be of two types which includes,

  • Syntax errors
  • Run time errors

Syntax Errors

Syntax errors occur due to improper use of various program components like operators and expressions. A simple example for syntax error is shown below.

As you know, there is a difference between the use of a single «equal to» and double «equal to». Using one instead of the other can lead to an error. One «equal to» refers to assignment while a double «equal to» refers to comparison. Similarly, we have expressions and functions having their predefined ways of implementation.

Another example for syntax error is shown below −

When we run the above program, we will get the following output −

Syntax errors are much easier to handle than run time errors since, the Lua interpreter locates the error more clearly than in case of runtime error. From the above error, we can know easily that adding a do statement before print statement is required as per the Lua structure.

Run Time Errors

In case of runtime errors, the program executes successfully, but it can result in runtime errors due to mistakes in input or mishandled functions. A simple example to show run time error is shown below.

When we build the program, it will build successfully and run. Once it runs, shows a run time error.

This is a runtime error, which had occurred due to not passing two variables. The b parameter is expected and here it is nil and produces an error.

Assert and Error Functions

In order to handle errors, we often use two functions − assert and error. A simple example is shown below.

When we run the above program, we will get the following error output.

The error (message [, level]) terminates the last protected function called and returns message as the error message. This function error never returns. Usually, error adds some information about the error position at the beginning of the message. The level argument specifies how to get the error position. With level 1 (the default), the error position is where the error function was called. Level 2 points the error to where the function that called error was called; and so on. Passing a level 0 avoids the addition of error position information to the message.

pcall and xpcall

In Lua programming, in order to avoid throwing these errors and handling errors, we need to use the functions pcall or xpcall.

The pcall (f, arg1, . ) function calls the requested function in protected mode. If some error occurs in function f, it does not throw an error. It just returns the status of error. A simple example using pcall is shown below.

When we run the above program, we will get the following output.

The xpcall (f, err) function calls the requested function and also sets the error handler. Any error inside f is not propagated; instead, xpcall catches the error, calls the err function with the original error object, and returns a status code.

A simple example for xpcall is shown below.

When we run the above program, we will get the following output.

As a programmer, it is most important to ensure that you take care of proper error handling in the programs you write. Using error handling can ensure that unexpected conditions beyond the boundary conditions are handled without disturbing the user of the program.

Источник

Lua Error Handling

Program run error handling is necessary, in our file operations, data transfer and web service invocation will appear in unexpected errors. If you do not pay attention to deal with error messages, according to the information will leak, can not run and so on.

Any programming languages, error handling is required. Error types are:

  • Grammatical errors
  • Runtime Error

Grammatical errors

Syntax errors are usually due to the program’s components (such as operators, expressions) caused by improper use. A simple example is as follows:

The above code is executed as a result of:

As you can see, there have been more than a syntax error, a «=» sign followed by two «=» sign is different. A «=» is the assignment expression two «=» is the comparison operation.

The above program will appear the following errors:

Syntax errors is easier than running a program error, run error unable to locate the specific errors, grammatical mistakes that we can quickly resolve, such as the above examples as long as we do in the for statement can be added:

Runtime Error

Run the program can perform error is normal, but it will output an error message. The following examples because the parameters input errors, program execution error:

When we compile and run the following code, the compiler can be successful, but at run time will produce the following error:

The following error message is caused because the program lacks the b parameter.

Error Handling

We can use two functions: assert and error to handle errors. Examples are as follows:

The above program will appear the following errors:

Example assert first checks the first argument, if no problem, assert does nothing; otherwise, the second argument as to assert error message thrown.

error function

: Terminates the function being executed, and returns the contents of the message as the error message (error function will never return)

Typically, error will be some additional information about the error message to the head position.

Level parameter indicates the position to get wrong:

  • Level = 1 [default]: To call error (file + line number)
  • Level = 2: function which calls the error function indicated
  • Level = 0: do not add error location

pcall and xpcall, debug

Lua error handling, you can use the function pcall (protected call) to wrap the code to be executed.

pcall receiving a function and you want to pass a parameter of the latter, and executed, the result: there is an error, no error; or the return value of true or false, errorinfo.

Syntax is as follows

pcall in a «protected mode» to call the first argument, therefore pcall capture function can perform any errors.

Typically when an error occurs, it is hoping to end up with more debugging information, not just where the error occurred. But pcall returns, it has destroyed part of the contents of the call Zhan.

Lua provides xpcall function, xpcall receiving a second parameter — an error handler when an error occurs, Lua error handler will be called before calling Zhan show to see (unwind), then you can use this function in debug library to obtain additional information about the error.

debug library provides two generic error handler:

  • debug.debug: Lua provide a prompt, allowing users to spread the wrong reasons
  • debug.traceback: According to Zhan call to build an extended error message

> = Xpcall (function (i) print (i) error ( ‘error ..’) end, function () print (debug.traceback ()) end, 33) 33 stack traceback: stdin: 1: in function [C]: in function ‘error’ stdin: 1: in function [C]: in function ‘xpcall’ stdin: 1: in main chunk [C]:? In false nil

xpcall Example 2:

The above program will appear the following errors:

Источник

Lua run time error occurred

This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.
The fourth edition targets Lua 5.3 and is available at Amazon and other bookstores.
By buying the book, you also help to support the Lua project.

8.5 – Error Messages and Tracebacks

Although you can use a value of any type as an error message, usually error messages are strings describing what went wrong. When there is an internal error (such as an attempt to index a non-table value), Lua generates the error message; otherwise, the error message is the value passed to the error function. In any case, Lua tries to add some information about the location where the error happened: The location information gives the file name ( stdin , in the example) plus the line number (1, in the example).

The error function has an additional second parameter, which gives the level where it should report the error; with it, you can blame someone else for the error. For instance, suppose you write a function and its first task is to check whether it was called correctly: Then, someone calls your function with a wrong argument: Lua points its finger to your function—after all, it was foo that called error —and not to the real culprit, the caller. To correct that, you inform error that the error you are reporting occurred on level 2 in the calling hierarchy (level 1 is your own function):

Источник

Exceptions¶

If any of the functions you register throws an exception when called, that exception will be caught by luabind and converted to an error string and lua_error() will be invoked. If the exception is a std::exception or a const char* the string that is pushed on the Lua stack, as error message, will be the string returned by std::exception::what() or the string itself respectively. If the exception is unknown, a generic string saying that the function threw an exception will be pushed.

If you have an exception type that isn’t derived from std::exception , or you wish to change the error message from the default result of what() , it is possible to register custom exception handlers:

translate_my_exception() will be called by luabind whenever a my_exception is caught. lua_error() will be called after the handler function returns, so it is expected that the function will push an error string on the stack.

Any function that invokes Lua code may throw luabind::error . This exception means that a Lua run-time error occurred. The error message is found on top of the Lua stack. The reason why the exception doesn’t contain the error string itself is because it would then require heap allocation which may fail. If an exception class throws an exception while it is being thrown itself, the application will be terminated.

Error’s synopsis is:

The state function returns a pointer to the Lua state in which the error was thrown. This pointer may be invalid if you catch this exception after the lua state is destructed. If the Lua state is valid you can use it to retrieve the error message from the top of the Lua stack.

An example of where the Lua state pointer may point to an invalid state follows:

There’s another exception that luabind may throw: luabind::cast_failed , this exception is thrown from call_function<> or call_member<> . It means that the return value from the Lua function couldn’t be converted to a C++ value. It is also thrown from object_cast<> if the cast cannot be made.

The synopsis for luabind::cast_failed is:

Again, the state member function returns a pointer to the Lua state where the error occurred. See the example above to see where this pointer may be invalid.

The info member function returns the user defined LUABIND_TYPE_INFO , which defaults to a const std::type_info* . This type info describes the type that we tried to cast a Lua value to.

If you have defined LUABIND_NO_EXCEPTIONS none of these exceptions will be thrown, instead you can set two callback functions that are called instead. These two functions are only defined if LUABIND_NO_EXCEPTIONS are defined.

The function you set will be called when a runtime-error occur in Lua code. You can find an error message on top of the Lua stack. This function is not expected to return, if it does luabind will call std::terminate() .

The function you set is called instead of throwing cast_failed . This function is not expected to return, if it does luabind will call std::terminate() .

Источник

A runtime error occured: /usr/lib/lua/luci/model/network.lua:187: attempt to index a nil value #2027

For whatever reason I am unable to re-open : #1649
I am again running a recent git head build :
commit 2a598bb
Author: Rafał Miłecki rafal@milecki.pl
Date: Fri Jul 27 21:54:08 2018 +0200

I have tracked this down to luci.ip returning nil for the the ipc.link(ifname) call.

I inserted debugging code in network.lua prior to the failing line (local phy_only = force_phy_only or (ipc.link(ifname).type

And got : Tue Jul 31 18:59:46 2018 daemon.err uhttpd[2337]: ipc.link(ifname) is nil wlan0

The subsequent call (ipc.link(ifname).type

= 1) then succeeded.

So for whatever reason on this device, very intermittently (like once a day) that call will fail and return nil, which network.lua then attempts to index with the .type call and it fails.

I attached the requested network interface dump to that report, but as I’ve been unable to re-open it I’ll reference it here : https://github.com/openwrt/luci/files/1897666/network.interface.dump.txt

I’m now not sure where to go next. Anyone have any ideas?

The text was updated successfully, but these errors were encountered:

The weird thing is that ipc.link() actually cannot return nil , except when there’s an out of memory issue: https://github.com/openwrt/luci/blob/master/libs/luci-lib-ip/src/ip.c#L1498

The only condition under which link() does not return at least an empty table is if (!msg || !cb)

Yep, understand that and have already trawled through that code.
I put some basic instrumentation in and logged several thousand calls per day, with at most one failure. The very peculiar thing is it will fail on the first call (always wlan0) and immediately succeed on the second. So call exactly the same thing twice and the first one fails but the second succeeds.

So by putting that debug in place I never see a failure backtrace. I only see the «is nil wlan0» as it will fail on the debug line and the next test passes.

As I said in the previous issue, I’m fairly sure it’s not a memory related issue :

# free
total used free shared buffers cached
Mem: 510936 226216 284720 548 4060 12632
-/+ buffers/cache: 209524 301412

This box literally does nothing other than shunt packets between the wireless and wired LAN. It’s a very expensive AP.

It has me stuffed, but as long as I have a web tab with the status overview up it happens pretty much every day.

I’ll put some instrumentation in ip.so to find out which allocation is failing and compile up a new image to test.

Debug printing from lua is easy enough. Is there a reference for getting a debug print out of the linked library you could point me towards?

Источник


Need for Error Handling

Error handling is quite critical since real-world operations often require the use of complex operations, which includes file operations, database transactions and web service calls.

In any programming, there is always a requirement for error handling. Errors can be of two types which includes,

  • Syntax errors
  • Run time errors

Syntax Errors

Syntax errors occur due to improper use of various program components like operators and expressions. A simple example for syntax error is shown below.

a == 2

As you know, there is a difference between the use of a single «equal to» and double «equal to». Using one instead of the other can lead to an error. One «equal to» refers to assignment while a double «equal to» refers to comparison. Similarly, we have expressions and functions having their predefined ways of implementation.

Another example for syntax error is shown below −

for a= 1,10
   print(a)
end

When we run the above program, we will get the following output −

lua: test2.lua:2: 'do' expected near 'print'

Syntax errors are much easier to handle than run time errors since, the Lua interpreter locates the error more clearly than in case of runtime error. From the above error, we can know easily that adding a do statement before print statement is required as per the Lua structure.

Run Time Errors

In case of runtime errors, the program executes successfully, but it can result in runtime errors due to mistakes in input or mishandled functions. A simple example to show run time error is shown below.

function add(a,b)
   return a+b
end

add(10)

When we build the program, it will build successfully and run. Once it runs, shows a run time error.

lua: test2.lua:2: attempt to perform arithmetic on local 'b' (a nil value)
stack traceback:
	test2.lua:2: in function 'add'
	test2.lua:5: in main chunk
	[C]: ?

This is a runtime error, which had occurred due to not passing two variables. The b parameter is expected and here it is nil and produces an error.

Assert and Error Functions

In order to handle errors, we often use two functions − assert and error. A simple example is shown below.

local function add(a,b)
   assert(type(a) == "number", "a is not a number")
   assert(type(b) == "number", "b is not a number")
   return a+b
end

add(10)

When we run the above program, we will get the following error output.

lua: test2.lua:3: b is not a number
stack traceback:
	[C]: in function 'assert'
	test2.lua:3: in function 'add'
	test2.lua:6: in main chunk
	[C]: ?

The error (message [, level]) terminates the last protected function called and returns message as the error message. This function error never returns. Usually, error adds some information about the error position at the beginning of the message. The level argument specifies how to get the error position. With level 1 (the default), the error position is where the error function was called. Level 2 points the error to where the function that called error was called; and so on. Passing a level 0 avoids the addition of error position information to the message.

pcall and xpcall

In Lua programming, in order to avoid throwing these errors and handling errors, we need to use the functions pcall or xpcall.

The pcall (f, arg1, …) function calls the requested function in protected mode. If some error occurs in function f, it does not throw an error. It just returns the status of error. A simple example using pcall is shown below.

function myfunction ()
   n = n/nil
end

if pcall(myfunction) then
   print("Success")
else
	print("Failure")
end

When we run the above program, we will get the following output.

Failure

The xpcall (f, err) function calls the requested function and also sets the error handler. Any error inside f is not propagated; instead, xpcall catches the error, calls the err function with the original error object, and returns a status code.

A simple example for xpcall is shown below.

function myfunction ()
   n = n/nil
end

function myerrorhandler( err )
   print( "ERROR:", err )
end

status = xpcall( myfunction, myerrorhandler )
print( status)

When we run the above program, we will get the following output.

ERROR:	test2.lua:2: attempt to perform arithmetic on global 'n' (a nil value)
false

As a programmer, it is most important to ensure that you take care of proper error handling in the programs you write. Using error handling can ensure that unexpected conditions beyond the boundary conditions are handled without disturbing the user of the program.

Program run error handling is necessary, in our file operations, data transfer and web service invocation will appear in unexpected errors. If you do not pay attention to deal with error messages, according to the information will leak, can not run and so on.

Any programming languages, error handling is required. Error types are:

  • Grammatical errors
  • Runtime Error

Grammatical errors

Syntax errors are usually due to the program’s components (such as operators, expressions) caused by improper use. A simple example is as follows:

-- test.lua 文件
a == 2

The above code is executed as a result of:

lua: test.lua:2: syntax error near '=='

As you can see, there have been more than a syntax error, a «=» sign followed by two «=» sign is different. A «=» is the assignment expression two «=» is the comparison operation.

Another example:

for a= 1,10
   print(a)
end

The above program will appear the following errors:

lua: test2.lua:2: 'do' expected near 'print'

Syntax errors is easier than running a program error, run error unable to locate the specific errors, grammatical mistakes that we can quickly resolve, such as the above examples as long as we do in the for statement can be added:

for a= 1,10
do
   print(a)
end

Runtime Error

Run the program can perform error is normal, but it will output an error message. The following examples because the parameters input errors, program execution error:

function add(a,b)
   return a+b
end

add(10)

When we compile and run the following code, the compiler can be successful, but at run time will produce the following error:

lua: test2.lua:2: attempt to perform arithmetic on local 'b' (a nil value)
stack traceback:
	test2.lua:2: in function 'add'
	test2.lua:5: in main chunk
	[C]: ?

The following error message is caused because the program lacks the b parameter.


Error Handling

We can use two functions: assert and error to handle errors. Examples are as follows:

local function add(a,b)
   assert(type(a) == "number", "a 不是一个数字")
   assert(type(b) == "number", "b 不是一个数字")
   return a+b
end
add(10)

The above program will appear the following errors:

lua: test.lua:3: b 不是一个数字
stack traceback:
	[C]: in function 'assert'
	test.lua:3: in local 'add'
	test.lua:6: in main chunk
	[C]: in ?

Example assert first checks the first argument, if no problem, assert does nothing; otherwise, the second argument as to assert error message thrown.

error function

Syntax:

error (message [, level])

: Terminates the function being executed, and returns the contents of the message as the error message (error function will never return)

Typically, error will be some additional information about the error message to the head position.

Level parameter indicates the position to get wrong:

  • Level = 1 [default]: To call error (file + line number)
  • Level = 2: function which calls the error function indicated
  • Level = 0: do not add error location

pcall and xpcall, debug

Lua error handling, you can use the function pcall (protected call) to wrap the code to be executed.

pcall receiving a function and you want to pass a parameter of the latter, and executed, the result: there is an error, no error; or the return value of true or false, errorinfo.

Syntax is as follows

if pcall(function_name, ….) then
-- 没有错误
else
-- 一些错误
end

Simple example:

> =pcall(function(i) print(i) end, 33)
33
true
   
> =pcall(function(i) print(i) error('error..') end, 33)
33
false        stdin:1: error..
> function f() return false,2 end
> if f() then print '1' else print '0' end
0

pcall in a «protected mode» to call the first argument, therefore pcall capture function can perform any errors.

Typically when an error occurs, it is hoping to end up with more debugging information, not just where the error occurred. But pcall returns, it has destroyed part of the contents of the call Zhan.

Lua provides xpcall function, xpcall receiving a second parameter — an error handler when an error occurs, Lua error handler will be called before calling Zhan show to see (unwind), then you can use this function in debug library to obtain additional information about the error.

debug library provides two generic error handler:

  • debug.debug: Lua provide a prompt, allowing users to spread the wrong reasons
  • debug.traceback: According to Zhan call to build an extended error message

> = Xpcall (function (i) print (i) error ( ‘error ..’) end, function () print (debug.traceback ()) end, 33) 33 stack traceback: stdin: 1: in function [C]: in function ‘error’ stdin: 1: in function [C]: in function ‘xpcall’ stdin: 1: in main chunk [C]:? In false nil

xpcall Example 2:

function myfunction ()
   n = n/nil
end

function myerrorhandler( err )
   print( "ERROR:", err )
end

status = xpcall( myfunction, myerrorhandler )
print( status)

The above program will appear the following errors:

ERROR:	test2.lua:2: attempt to perform arithmetic on global 'n' (a nil value)
false

Chapter 6. Handling and Avoiding Errors

Program correctness matters on every count, from user acceptance and trust to the downstream consequences of program output. In this chapter, you learn about the following:

· The kinds of errors that can occur in your programs

· Lua’s mechanisms for handling errors

· Techniques to avoid program errors

· Techniques to locate program errors

Along the way, you’ll become familiar with Lua’s I/O library, which is included in some of the examples.

Kinds of Errors

Some flaws can turn up before a program is executed. These are compile-time errors, which Lua can find as it converts your source code into executable bytecode. Often these result from simple misspellings or typing slips as you edit your source code. Other flaws are more insidious — Lua recognizes them as syntactically correct so they make their way into the executable bytecode. These errors await discovery at run time, preferably by you during testing rather than by someone who’s actually using a product after it’s been released with the erroneous code.

Syntax Errors

Syntax refers to the way various language elements are allowed to fit together, completely independent from the meaning of those elements. A programming language like Lua is necessarily fussy about syntax, because source code expressed in it needs to translate unambiguously to byte-code, the instructions that Lua’s virtual machine can deal with. During the 1960s (the renaissance era of modern programming languages) computer science practitioners such as Niklaus Wirth understood the importance of specifying syntactic rules that express naturally and simply the intent of a programmer. Lua’s syntax falls neatly into this heritage. Take time to study the page in the Lua manual that describes Lua’s complete syntax. Doing so can provide much insight into the Lua language and the way the Lua parser operates.

Essentially, it is the job of Lua’s parser to recognize syntactically correct Lua programs and, in the case of an incorrect program, to let you know where the problem is. Of course, the program you submit to Lua might have more than one syntax error, but Lua will stop at the first one it encounters and print a message that should allow you to pinpoint the location of the problem. Usually, but not always, you’ll instantly recognize the offending construction, make a quick fix, and compile the code again.

Here is an example of a syntax error:

a = 1 + + 2

This results in an «unexpected symbol near ‘ + ‘ ” message.

Here’s another example:

for do

Lua expects a variable name to follow for, so it generates a ”‘<name>’ expected near ‘do’ ” message.

And here’s an erroneous script example:

Str = ‘hello, world

The result is the message «unfinished string near »hello, world’ «. When you run this as a non-interactive Lua script, this error is generated immediately. When you type it in interactively, Lua presents you with a continuation prompt and defers the error until you provide more input. Strings that begin with a single or double quote must end, on the same line, with a matching quote. Lua supports multiline strings, for which you use the [[ ]] notation (or represent each newline with a backslash-escaped n or backslash-escaped newline, as described in Chapter 2).

Now take a look at this example:

break

By itself, this command results in the message «no loop to break near ‘<eof>‘ » (where <eof> refers to «end of file»).

Here’s a function call example:

Fnc

(42)

Lua generally allows you to put whitespace, including line endings, wherever you like. As mentioned in Chapter 3, however, calling a function is an exception: The opening parenthesis must occur on the same line as the function expression. The preceding construction leads to the message»ambiguous syntax (function call x new statement) near ‘(‘.»

Now look at this:

Tbl:Fnc 4

This results in the message «function arguments expected near ‘4′.» When Lua sets up a method call, it expects the usual function argument specification: a list of zero or more arguments wrapped in parentheses, a single quoted string, or a single table constructor.

In the following example, the vararg expression … is used inside a function whose parameter list does not end in …:

function Fnc() print(…) end

This results in the message «cannot use outside a vararg function near ‘…’ «A Lua script, whether it is a single line entered interactively in the Lua interpreter or a complete file that has been loaded noninteractively, has an implicit … that contains any arguments with which it is called.

In the case of a single line entered in the Lua interpreter, there can’t be any arguments, but still you can see that the following statement is valid:

print(… )

Unlike named parameters, the … expression has limited visibility and cannot be used as an upvalue.

For more on upvalue, see Chapter 3

These are contrived examples—you’ll rarely, if ever, see some of these syntax error messages. Or if you do get an error message from Lua, it may not make immediate sense. For example, if you enter the following:

string.sub9″Hello», 1, 1)

it will return the message «unexpected symbol near ‘,’.» You can easily recognize the last problem as a typing mistake in which «9» was typed instead of «(«, so what accounts for Lua’s error message? Recall that Lua permits the parentheses to be omitted when calling a function with a single string argument. In this case, Lua treats string.sub9 as a global function that, at run time, will be passed the string «Hello». In this context, the comma that follows «Hello» doesn’t make sense, and Lua lets you know about it.

Some programming languages require variables to be declared before use. When programs written in these languages are compiled, any reference to an undeclared variable will be reported as an error. This is not the case with Lua. Any variable name that does not match an in-scope local variable name is considered to be one that will be resolved at run time in the global environment.

Some very uncommon compile-time errors have to do with internal limits rather than syntax violations. We’ve never encountered any of these in practice or heard of them occurring. But, in the spirit of inquiry and with a hammer in hand, give it a try. The following Lua program generates another Lua program, one that contains an impracticably large number of nested do blocks. In the first program, a routine is called recursively to generate a text file that simulates a handwritten Lua script. Here are the contents of the recurse.lua script:

function Recurse(Count, Indent)

Indent = Indent or «»

if Count > 0 then

io.write(Indent, «don»)

Recurse(Count — 1, Indent .. » «)

io.write(Indent, «endn»)

end

end

Recurse(299)

Now attempt to compile the program that this script generates:

lua recurse.lua | lua

The pipe directs the output of the first program to the input of the second. Note that, in the spirit of the Unix tool philosophy, the Lua interpreter acts like a filter when its standard input is not a terminal. This results in the following message:

stdin:200: chunk has too many syntax levels

Notice the line number that seems to indicate that Lua was okay with nesting blocks just up to that limit. In practice, your nested blocks will never exceed even a small fraction of that number. But this limit and other limits involving expression complexity are worth keeping in mind if you ever automatically generate Lua programs.

The Call Stack

When a function is called in Lua, space needs to be set aside to hold local variables and certain bookkeeping information such as where program control should resume when the function returns. Because Lua functions are reentrant (that is, there can be multiple outstanding calls to the same function at a given time), this storage must be bound to a particular function call rather than just to the function itself. When Lua compiles a program, it knows how much space needs to be reserved for a particular function, but the actual contents of that space aren’t known until the function is actually called. The simplest solution that meets these requirements is a last-in first-out stack. This is a data structure in which items to be stored are pushed onto the top of the stack, increasing its size, and items to be retrieved are popped from the top of the stack, decreasing its size. When a function is called, its stack frame is pushed onto the call stack, and when it returns, that frame is popped, making the vacated space available for other function calls.

The details of the call stack are hidden from general view. As a Lua programmer, you want to keep in mind that a stack is being used behind the scenes to make sure that function calls work as expected, but in general you won’t need to be aware of its implementation or details. For the times when you do need a window into your program’s internal environment, Lua provides a debugging library. You can use one of its functions, debug.traceback, to generate a list of pending function calls, essentially an overview of the call stack. The debug.traceback function augments the string you pass it with such a list.

1 function B()

2 print(debug.traceback(«B»))

3 end

4

5 function A()

6 print(debug.traceback(«A 1»))

7 B()

8 print(debug.traceback(«A 2»))

9 end

10

11 A()

The output that this program generates has a strong resemblance to the error messages that were shown earlier:

A 1

stack traceback:

trace.lua:6: in function ‘A’

trace.lua:11: in main chunk

[C]: ?

B

stack traceback:

trace.lua:2: in function ‘B’

trace.lua:7: in function ‘A’

trace.lua:11: in main chunk

[C]: ?

A 2

stack traceback:

trace.lua:8: in function ‘A’

trace.lua:11: in main chunk

[C]: ?

Notice that the traceback doesn’t give you a history of function calls. For example, you won’t find any reference to the print function. What it does show you is a list of functions that have been called but that have not yet returned. The topmost indented line indicates the location in the Lua script where debug.traceback was called. Each line beneath that shows a pending function and the line number from which it was called. These lines are shown with the most recently called functions first. The bottom line indicates that the first function call originated in a C function for which no line number information is available.

Runtime Errors

When a Lua source file is successfully compiled into bytecode and executed by the interpreter, an error results in a descriptive message followed by a stack traceback. Here’s an example:

function C()

print(1 + nil)

end

function B()

C()

end

function A()

B()

end

A()

When this runs, Lua prints the following:

lua: err.lua:2: attempt to perform arithmetic on a nil value

stack traceback:

err.lua:2: in function ‘C’

err.lua:6: in function ‘B’

err.lua:10: in function ‘A’

err.lua:13: in main chunk [C]: ?

In addition to the message that describes what went wrong during program execution and on which line, there is also a stack traceback section. That portion of the output is a snapshot of pending func-tion calls and provides you with the context of the error. It’s important to have a good grasp of how call stacks operate in Lua, not only for reading stack tracebacks, but also for writing programs that work well with Lua’s error-handling system.

Handling Errors

As you develop a program, there are a number of ways you can deal with the inevitable errors that crop up. Your best course of action will be dictated by the following:

· How the program is to be used and its targeted user

· Whether the error is surmountable

· Whether the error is code-related or data-related

Default Error Behavior

The default behavior of the standalone Lua interpreter when it encounters an error condition is to print a message followed by a stack traceback and then to terminate the program, like this:

local function Fnc(A, B, C)

print(A + B + C)

end

print(«Position 1»)

Fnc(1, nil, 3)

print(«Position 2»)

The output includes the expected error and also shows that «Position 2» was never reached:

Position 1

lua: err.lua:2: attempt to perform arithmetic on local ‘B’ (a nil value)

stack traceback:

err.lua:2: in function ‘Fnc’

err.lua:6: in main chunk

[C]: ?

For many quickly written scripts that are intended to be run by the developer, this behavior is acceptable. In these cases, the runtime error can be treated as if it was a syntax error —that is, you can identify the problem, correct it, and run the script again, repeating the process until the program does what you want it to do.

In the context of a program used in the real world, Lua’s default response to errors is rather draconian. It is bad form to abruptly terminate a program while a network connection, database connection, or file is still open. Buffers may not have been flushed and system resources may not be freed in a timely or consistent manner. In the case of a program with a user interface, it can be more than annoying to have a program abnormally end. A considerable amount of work may be lost when a program crashes.

Checking Assumptions

When you track down the source of runtime errors, you may find that certain assumptions you made have proved to be invalid. For example, you may have implemented a loop in which you assume the value of some variable will never exceed a certain number, or you may have written a function that requires a string as its first argument. The problem is that the consequences of an invalid assumption might occur far from its source. Sometimes, errors occur with such irregularity that it is hard to even know where to start looking. These can stem from multiple invalid assumptions that by themselves don’t cause apparent problems, but wreak havoc in combinations that might occur infrequently. Avoid these oblique issues by testing your assumptions directly. Lua makes this easy for you with the assert function, as shown in this example:

local function Quote(Str)

assert(type(Str) == «string», «Str is not a string»)

return string.format(«%q», Str)

end

print(Quote(‘Huckleberry «Blue» Hound’))

print(Quote(1))

This outputs the following:

«Huckleberry «Blue» Hound»

lua: test.lua:2: Str is not a string

stack traceback:

[C]: in function ‘assert’

test.lua:2: in function ‘Quote’

test.lua:7: in main chunk

[C]: ?

The idea here is that it is far better to terminate an errant program the moment you know something has gone wrong than to let the problem become clouded by further processing. Keep in mind that this is a development technique that is intended to address problems with program infrastructure —that is, things over which you as the developer have control.

Stack Tracebacks and End Users

Abnormal program termination may occur repeatedly as you develop a script and consequently you can become accustomed to stack tracebacks. However, an end user who encounters a stack traceback won’t have a clue what it means and will inevitably lose some trust in your program. Treat stack tracebacks as a symptom of a bug that should not make it past the development stage. To emphasize this, you may want to display stack tracebacks with the header Programmer error. Later in this chapter, you’ll see how to avoid the conditions that generate stack tracebacks, but first you’ll learn a technique to intentionally generate them and the circumstance in which you should.

Code Errors

View your program as comprising code on one hand and data on the other. Code is the fixed deliverable made up of program statements and data is the material your program processes at run time. Calls to assert are an appropriate way of dealing with code errors. The program you deliver should be free of coding errors, and if abnormal endings and stack tracebacks get you closer to eliminating them, then using assert is fully warranted.

Data Errors

Data errors are by their nature different than code errors. Essentially, your job here is to make your program respond gracefully when garbage is shoveled into it, because sooner or later, intentionally or not, your program’s input domain will be taxed grievously. Your best approach is to mistrust all data that your program reads—the closer to the source, the better.

In the preceding example, you have control over the type of value that you pass to the Quote function. You may not, however, have control over the string’s value, which may have been entered by the user into a text field. If the string itself needs to conform to certain patterns for the program to function correctly, that should be checked and handled by some user-friendlier means than assert. Of course, you may use assert to ensure that your string screening logic is working as expected, because if it isn’t, you’ve got some code adjustments to make.

The assert and error Functions

You don’t have to leave it up to Lua to issue errors. There may be circumstances in which your program should issue an error itself, and for these cases, Lua provides the assert and error functions. Use the assert function to issue an error if an assumption proves to be invalid at run time. To issue an error unconditionally, no questions asked, use the error function.

One or more values are passed to the assert function. These values may be passed in directly, but usually they are the results of an expression such as a function call. If the first argument is either false or nil , assert generates an error and prints an error message followed by a stack traceback. If a second argument is present, it is used as the error message; otherwise, the string «assertion failed!» is used. If the first argument is neither false nor nil , then assert returns every argument that was passed in:

function Reflect(A)

return A, 1, 2, 3

end

print(assert(Reflect(0)))

print(assert(Reflect(nil)))

This displays the following:

0 1 2 3

lua: test.lua:6: 1

stack traceback:

[C]: in function ‘assert’

test.lua:6: in main chunk

[C]: ?

The assert function is a wrapper for the more general error function, which you can be use to unconditionally generate an error.

Defining Your Own Error Condition

Lua has a well-defined set of conditions under which an error will occur. Using the error function, you can define your own as well. Here’s how:

function Answer(Question)

local Res

if Question == «no bananas» then

Res = «yes»

elseif Question == «everything» then

Res = 42

elseif Question == «Tuesday» then

Res = «Belgium»

else

error(«No answer for » .. tostring(Question))

end

return Res

end

print(Answer(«this statement is false»))print(Answer(«this statement is false»))

Running this results in the following:

lua: answer.lua:10: No answer for this statement is false

stack traceback:

[C]: in function ‘error’

answer.lua:10: in function ‘Answer’

answer.lua:15: in main chunk

[C]: ?

The same error-handling mechanism is used for user-generated errors as for those originating in the Lua core.

You can pass an integer as an optional second argument to error. Passing 0 suppresses line number information in the error message. If you specify the value 1 (the default if the argument is missing), the line number where error was called will be displayed. A higher value tells Lua how far down on the call stack to reach to determine which line number to display. This is useful if you write an error handler that in turn calls error. In this case, you don’t want to mislead the programmer by displaying a line in your handler; you want to show the line where the call to your handler was made, so a value of 2 is appropriate.

Anticipating Error Conditions

One way to cope with the problem of runtime errors is to diligently check for the conditions that can lead to an error. For example, a function that prints the sum of its three arguments could be written as follows:

local function Fnc(A, B, C)

A, B, C = tonumber(A), tonumber(B), tonumber(C)

print(A and B and C and A + B + C

or «Three numbers expected»)

end

print(«Position 1»)

Fnc(1, «2», 3)

print(«Position 2»)

Fnc(1, «Lua», 3)

print(«Position 3»)

Here, where the conditions needed to calculate and print the sum of three numbers are not met, an alternative is printed instead:

Position 1

6

Position 2

Three numbers expected

Position 3

After reaching position 3, the program terminates normally, even though the values passed in the second call to Fnc included a nonnumeric value.

Anticipating an error condition allows you to handle the situation appropriately. For example, in an interactive program you could allow the user to specify an alternate course of action or to repeat an action with different input values. If it is appropriate to terminate the program, at least this can be done gracefully, closing open resources as needed and reporting the condition in an expected fashion.

Working with Return Values

Because the preceding example uses the print function, its use is restricted to programs that can work with the standard output channel. Its output is directed to the user rather than the caller. In all but the simplest cases, you’ll want to avoid this kind of restriction by making your functions independent of the kind of program that uses them. This practice enables you to build up a library of functions that should be portable to different platforms. The key to this is to have functions and their callers communicate by means of parameter lists and return values. The actual input and output to the system can then be handled at a higher level by the caller of the platform-independent functions.

One of Lua’s many distinctive features is that it allows functions to return multiple values. A convention has evolved regarding how functions should indicate success and failure. If a function succeeds, its first return value should be something other than false or nil. Usually this return value is the principal value the function was called on to produce, like a file handle or string capture. This value can be followed by other pertinent values. If the function fails, its first value should be nil. This is followed by something that explains why the error occurred, usually an error message but possibly something else like a table or numeric error code.

The example can be reworked to follow this convention:

local function Fnc(A, B, C)

local Sum, ErrStr

A, B, C = tonumber(A), tonumber(B), tonumber(C)

if A and B and C then

Sum = A + B + C

else

ErrStr = «Three numbers expected»

end

return Sum, ErrStr

end

print(«Position 1»)

local Sum, ErrStr = Fnc(1, «2», 3)

print(Sum or ErrStr)

print(«Position 2»)

local Sum, ErrStr = Fnc(1, nil, 3)

print(Sum or ErrStr)

print(«Position 3»)

The output is like that of the previous example:

Position 1

6

Position 2

Three numbers expected

Position 3

You’ll occasionally see a clever use of assert that utilizes Lua’s return value convention. For example:

Hnd = assert(io.open(«index.html», «r»))

The io.open function returns nil followed by an error message if the file cannot be opened; otherwise, it returns the handle to the opened file. In either case, these return values are passed directly to assert. In the event that io.open fails, the first argument to assert will be nil. This causes assert to issue a runtime error using as its error value the second argument it receives, namely the error message returned by io.open. If, on the other hand, io.open succeeds, assert receives as its first argument the handle to the open file. Because this value is neither false nor nil, it simply returns this value and does not issue an error.

The problem with using assert is that, in the event of a failed assertion, the default action is to terminate the program. In the case of the example shown here, there may be good reasons why the file index.html cannot be opened, and to bring the entire program to a halt just because the file can’t beopened is especially heavy-handed. In the next section, you’ll learn about structured programming techniques that let you recover gracefully and simply from conditions like this. The assert function is extremely useful for ferreting out wrong assumptions in your code, but it’s not the best approach to handle conditions that are beyond the programmer’s control.

Another convention has evolved to handle the returns values of a function that is called indirectly through another function. Like all values in Lua, a function is a first class value and can be passed as an argument, something you’ve already seen with the comparison function that can be optionally passed to table.sort. In some cases, a function’s job can simply be to call another function in a modified runtime environment. The pcall and xpcall functions (described later in this chapter) are examples of this. However, the added indirection requires some means to distinguish between errors caused by the function that is called directly and the one that is called indirectly. Typically in this case, the directly-called function returns true if it succeeds; this is followed by the return values of the indirectly-called function whether it succeeds or fails. If the directly-called function fails, it returns false followed by an error message.

Structuring Code

In the examples you’ve seen so far, the program code has been structured to visually indicate the blocks as Lua sees them. For example, the statements following an if expression are indented to show what gets executed if the expression evaluates to true. The benefit to this structuring is that you can tell at a glance what state the program is in—for example, which files are open and which conditions are currently met.

Following is an example that uses Lua’s return value convention with structured programming to generate a file listing with line numbers. It shows how error handling can be integrated with block structuring to handle errors in a predictable and robust way. As you study the example, ask yourself what happens under different scenarios. For example, what happens to the source file handle if the destination file cannot be opened?

local function FileCopyLineNum(SrcFileStr, DstFileStr)

local SrcHnd, DstHnd, ErrStr, Line

SrcHnd, ErrStr = io.open(SrcFileStr, «r»)

if SrcHnd then

DstHnd, ErrStr = io.open(DstFileStr, «w»)

if DstHnd then

Line = 0

for Str in SrcHnd:lines() do

Line = Line + 1

DstHnd:write(Line, » «, Str, «n»)

end

if Line == 0 then

ErrStr = SrcFileStr .. «: File is empty»

Line = nil

end

DstHnd:close()

end

SrcHnd:close()

end

return Line, ErrStr

end

local Count, ErrStr = FileCopyLineNum(«index.html», «index.lst»)

io.write(Count and («OK: count » .. Count) or ErrStr, «n»)

If index.html does not exist, this script outputs the following:

index.html: No such file or directory

If this file exists but is empty, the output is this:

index.html: File is empty

If index.html exists and has lines in it, and index.lst can be opened for writing, the output looks like this:

OK: count 243

The general idea behind structuring your code is to place operations in their correct position. For example, an indented block follows the conditional statement that tests whether the source file has been successfully opened. You can bring much clarity to your code by ensuring that this condition remains valid through the entire block, and that the condition is invalid outside of the block. In this example, that’s done by closing the source file at the very end of the conditional block. You don’t need to check whether the file is currently open and ready to be closed —the block structure guarantees that it is, regardless of . what happened inside the block. Whether or not the destination file is successfully opened, you know .

from the visual representation of the code where the source file is open and where it needs to be closed.

Why would it be a problem to close the source file as soon as its contents have been copied? A glance at the indentation of the code should tell you immediately: the source file would not be properly closed if an error occurred while opening the destination file.

Lua enables you to keep your program clear by declaring local variables only where you need them, that is, to keep their scope at a minimum. Here, the declaration of DstHnd could have been deferred to the point after the source file has been opened. However, the declaration of Line and ErrStrneed to be where they are, because they are used as return values. Furthermore, neither should be redeclared in an inner block because this would mask the outer values. Beginners to Lua often wish that variables would be local by default, but doing so would make this powerful form of scope control impossible.

Notice that no assumptions about the user interface are made in the FileCopyLineNum function. Communication with this function occur through its parameter list and its return values.

A slight visual problem occurs in the destination file when the number of digits in the line number changes. This can be remedied with string formatting, as described in Chapter 5.

Bigger problems have to do with guarding against unintended input. What if the function is called with nonstring arguments? What if a binary file is specified as the source file? Worse still, what if an important system file is specified as the destination file?

Calling the function with nonstring arguments is a code issue, and in this case you’ll learn about the problem when you call io.open. Like a syntax error, after you correct the problem, it won’t be an issue anymore. If this routine merely stored the arguments for later processing, some assertions might be necessary to ensure that each argument is a string.

As written, the FileCopyLineNumfunction assumes that the source file is a text file. In the copy loop, you could check for the presence of unexpected characters or unexpectedly long source lines. If either of these occurs, you could terminate the loop and proceed appropriately.

The risk of overwriting an important file is more difficult to address. The relevant question is whether this routine is at the right level to implement a safeguard. Clearly, io.open isn’t making the check, and it could be convincingly argued that FileCopyLineNum shouldn’t either. If it doesn’t, the burden is on the caller to make sure that the destination file is safe to create or overwrite. The important lesson is that you need to consider these issues and strive to cover them at the right place in your code.

Even if the block following a resource test does not itself contain nested indented blocks, it is still a good policy to defer closing the resource until the end of the block, because as you refine the program and possibly add new conditionals, knowing that the resource is open throughout the block is one less thing you have to verify.

Some programmers criticize, sometimes with alarming fervor, this type of code structuring, complaining that indentation levels can become excessive and that even small changes to a routine’s logic can necessitate shifting large blocks to the left or right (something that is easy to do in a decent text editor). In practice, deep nesting indicates a need to break blocks into functions. Doing so makes your program more modular and reduces the degree of indentation. The functions in the following example are fictitious and, for simplicity’s sake, are called without any arguments and portrayed without error handling:

A = ResourceOpen()

if A then

B = ItemFirst()

while B do

C = ResourceOpen()

if C then

for D in E() do

if F then

DoSomething()

end

end

ResourceClose(C)

end

B = ItemNext(B)

end

ResourceClose(A)

end

This can be rewritten as follows:

function Moon(B, C)

for D in E() do

if F then

DoSomething()

end

end

end

function Sun(B)

C = ResourceOpen()

if C then

Moon(B, C)

ResourceClose(C)

end

end

A = ResourceOpen()

if A then

B = ItemFirst()

while B do

Sun(B)

B = ItemNext(B)

end

ResourceClose(A)

end

Error-Containment Functions

In the examples you have seen so far, runtime errors result in the termination of the entire program. Fortunately, this can be avoided. Lua provides a mechanism — the protected environment—to contain the damage caused by an error condition. The Lua pcall and the xpcall functions enable you to suppress the propagation of an error.

The pcall Function

Any Lua function, including Lua scripts loaded from disk and converted to a function by loadfile, can be run in a protected environment. You do this by calling pcall with the function to be called as its first argument. Additional arguments to pcall are passed as arguments to this function. The principal difference between calling a function directly and calling it through pcall is the way errors are handled. As you’ve seen so far, if an error occurs in a function that is called directly, the Lua interpreter responds by displaying the stack traceback and terminating the program. If, on the other hand, an error occurs in a function that has been invoked by pcall, the error is reported as one of the return values of pcall. You can handle the error in whatever way you consider appropriate.

Try It Out

Using pcall

In this Try It Out, you’ll see the pcall function in action. The following code is a revision of the first example from this chapter adapted to run in a protected environment.

1. With your text editor, create a new file with the following contents:

function C()

print(«C 1»)

print(1 + nil)

print(«C 2»)

end

function B()

print(«B 1»)

C()

print(«B 2»)

end

function A()

print(«A 1»)

B()

print(«A 2»)

end

print(«Main 1»)

local Code, ErrStr = pcall(A)

print(«Main 2», Code and «Success» or ErrStr)

2. Save this script as err.lua.

3. Run the script with the Lua interpreter, like this:

lua err.lua

The output is as follows:

Main 1

A 1

B 1

C 1

Main 2 err.lua:3: attempt to perform arithmetic on a nil value

How It Works

The main clue to understanding what happened is the lack of «C2», «B2», and «A 2» markers. If this gives you the notion that when the error occurred control was transferred directly back to pcall, you’re entirely correct.

Remember, it is the call stack that allows functions to return properly. In effect, the stack is Lua’s only memory regarding where it came from and where it should return to. The pcall function effectively marks the current position on the stack and arranges with Lua to return to that mark—the recover point—in the event of an error. Up until the error occurred, the stack functioned as expected. You can follow this in more detail by adding a call to debug.traceback in the print statements. For example, replace print(«A 1») with print(debug.traceback(«A 1»)).

A protected call will keep your program from sinking after a runtime error, but it may tilt frightfully to starboard. Imagine that the «A 1», «B1», and «C 1» markers indicate positions where resources such as database connections and files are opened, and the markers «A 2», «B 2», and «C 2» indicate the positions where the resources are closed. When pcall returns with a return code indicating that an error took place, it may be difficult to programmatically determine which resources are in need of closing.

Some resources—in such as userdata resources that have been specially programmed—will close themselves when they are no longer accessible to your program and are consequently collected as garbage. Using Lua’s C programming interface, you can create resource handles to behave this way. However, you should not depend on this behavior to close resources. A very large number of open resources may accumulate between garbage collection cycles, and this can have an adverse effect on the operation of your program.

Another method to manage dangling resources is to pass a newly constructed local table to your function by means of pcall. You can use this table to store handles for open resources, among other things. When a resource is opened, its handle is stored in the table. After the resource is closed, its handle is set to nil . This table would be passed as an argument to all functions in the call chain. Unfortunately, this approach couples these functions in a way that may be undesirable. It also means that the caller of the protected function must know, given an assortment of handles, how to close the resources. A variation on this theme would be to store a closure that would close the resource instead of a resource handle.

The caller of a protected function must also, in the event of an error, determine the best subsequent course of action. Should the program clean up and terminate? Should it invoke the protected function again with different arguments? One action your program should definitely not take is to proceed as if nothing happened.

The xpcall Function

You may have noticed that the error message returned by pcall does not have a stack traceback. After pcall returns, all stack levels between pcall and the place where the error occurred are no longer . accessible, so no traceback can be constructed. The xpcall function is like pcall, except that you specify as its second argument an error handler that is called before Lua transfers control back to the place where xpcall was called. This handler receives the error message and returns the new error value, usually the same error message after it has been augmented with a stack traceback. Thexpcall function differs from the pcall function in two respects:

· It uses an error handler.

· It is unable to pass arguments to the function it calls.

Here’s an example of its use:

function A()

print(1 + nil)

end

print(xpcall(A, debug.traceback))

This outputs the following:

false err.lua:2: attempt to perform arithmetic on a nil value

stack traceback:

err.lua:2: in function <err.lua:1>

[C]: in function ‘xpcall’

err.lua:5: in main chunk

[C]: ?

Here, the debug.traceback function was used as a handler, but you can write your own as well. It can return something other than an error string if you want.

User-Written Scripts

Many applications employ Lua so that users can prepare and run their own extension scripts. However, you should run these scripts in protected mode to contain any errors that may occur.

Most users have experienced programs that run fine as long as nothing unexpected occurs, but operate erratically after they attempt to recover from an error. If your application supports the execution of user-provided Lua scripts, you need to guard against destabilizing your entire application as a result of running an errant script. As you learned in Chapter 4, Lua provides sandboxing mechanisms to isolate these user-written scripts from each other and from the host application. In the next chapter, you’ll see that Lua supports a way to require that only local variables be created by a script. Doing this helps to ensure that resources are cleaned up properly in the event of an error. Similarly, functions that could pose a risk to the operating environment are easily made unavailable to the user-written scripts.

Locating Errors

The diagnostic message and stack traceback that Lua presents when a runtime error occurs are often sufficient for you to identify exactly what went wrong. However, sometimes an error occurs long after the source of the problem has been executed. For example, an error might indicate that arithmetic was attempted on a nil value, and you are left wondering how a certain variable ever became nil. A good approach when you don’t have a clue where something like this may have occurred is to use the print function or a message box routine to temporarily display important values at various points where you think the problem may have originated. But rather than sprinkling such calls haphazardly throughout your code, you’ll usually do better by attempting to repeatedly divide the problem area in half.

Summary

In this chapter, you’ve learned to do the following:

· Look for and correct syntax errors.

· Handle runtime errors (both code-based and data-based).

· Understand Lua’s call stack.

· Use assert when it’s desirable to do so.

· Read stack tracebacks.

· Structure your code with an emphasis on resource lifespan.

· Protect a function call so that the entire application isn’t abnormally ended if it causes a runtime error.

Any mechanism that enables you to understand the internal state of your program is valuable in ensuring that it is functioning as expected or in uncovering errors. In the next chapter, you’ll learn about Lua modules, and one of the examples shows you how to generate a tree diagram of Lua tables. A rendering like that can provide a lot more information than a simple print statement can and is consequently a good tool to have when tracking down program errors.

Exercises

1. In the Lua interpreter, issue the following statement:

> print(1 + nil)

Why doesn’t print show up in the resulting stack traceback?

2. How would you add the prefix ‘Programmer error’ to the stack traceback?

3. The pcall function accepts arguments, and the xpcall function accepts an error handler. How can you write a protected function caller that accepts both arguments and an error handler?

Attempt to call a nil value

Description: calling a function that doesn’t exist

printtt(«abc») — printtt is not a function

test() — calling before it’s defined, same error

Unexpected symbol near ‘something’

Description: an invalid character is placed next to a value/keyword/variable/function call

function abc()) end — unexpected symbol near ‘)’

a l= 15 — unexpected symbol near ‘l’

local a = 5] — unexpected symbol near ‘]’

Attempt to index global ‘variable’ (a nil value)

Description: indexing via [key] or .key for a variable that doesn’t exist

abc.x = 5 — abc is nil, error

abc = {} — abc defined here

xyz[‘x’] = ‘abc’ — xyz is nil, error

Attempt to perform arithmetic on a nil value

Description: performing arithmetic (*, /, -, +, %, ^) on a nil value

print(xyz + 5) — error, xyz not defined

a = a + 5 — error, a not defined

Attempt to perform arithmetic on field ‘?’ (a nil value)

Description: performing arithmetic (*, /, -, +, %, ^) on a nil value

Attempt to compare nil with <TYPE>

Description: using a comparison operator (<, >, ~=, ==, >=, <=) in which one side is a nil value

print(x < y) — y is not defined

Malformed number near <NUMBER>

Description: the number has an invalid character next to it

print(12345aaa) — aaa makes it a malformed number

Unfinished capture | Malformed pattern

Description: the pattern is missing a closing ), or a closing ]

print(string.match(‘ABC’, ‘(‘)) — unfinished capture

print(string.match(‘ABC’, ‘[‘)) — malformed pattern

When you get an error, Lua provides a stack trace showing you where it originates from, where the error occurs, the function calls that led to the error, and the line number of where it occurred.

A general error will look like this:

file_location:LINE NUMBER: error message

file_location:LINE NUMBER: in <local/function> ‘FUNC’

file_location:LINE NUMBER: in main chunk

C:Usersuserlua_file.lua:5: attempt to perform arithmetic on a nil value (field ‘x’)

C:Usersuserlua_file.lua:5: in local ‘c’

C:Usersuserlua_file.lua:7: in local ‘b’

C:Usersuserlua_file.lua:9: in function ‘a’

C:Usersuserlua_file.lua:12: in main chunk

The code that resulted in this error is:

Here you can see the line number 5 after the file location, which tells us where the exact line with the code that resulted in the error. The stack traceback shows the functions that were called that led up to that.

First, function a is called at line 12, then function b is called at line 9 inside of a, then c is called at line 7 inside of function b, and finally at line 5, the error occurs inside of function c.

A note to add is that comments can offset the line number and make it appear as the error is in a line that doesn’t exist or doesn’t look like an error,

error handling

dynamic link

  1. In Lua, dynamic links are considered the parent of all other mechanisms

  2. So you can use it to dynamically load any other mechanism not in Lua

  3. Two parameters required for package.loadlib

    1. Full path to the library
    2. Correct function name
  4. The loadlib function loads the specified library and links it into Lua

  5. It does not call any functions in the library

  6. Instead, a function written in C is returned as a Lua function

  7. If an error occurs while loading the library or looking for the initialization function, nil and an error message are returned

local path = "c:/lua/5.1/socket.so"
local f = package.loadlib(path, "luaopen_socket")
  1. Usually use require to load the C library. This function will search the specified library
  2. Then load the library with loadlib and return the initialization function
  3. This initialization function should register the functions provided in the library with Lua, just like other functions defined in the Lua code block

error

  1. Lua is an extension language, usually embedded in applications

  2. If we crash or exit directly when an error occurs, we can’t capture where the error occurred

  3. So whenever Lua has an error, it should end the current block and return to the application

  4. Any unexpected condition in Lua causes an error, such as:

    1. Add two non numeric values
    2. Call on a value that is not a function
    3. Index a value that is not a Table
  5. You can explicitly raise an error by calling the error function

    1. Function that needs to pass in an error message
do
    print("enter a number:")
    n = io.read("*number")
    if not n then 
        error("invalid input")
    end
end
 
-- Equivalent to the above code
do
	print("enter a number:")
	n = assert(io.read("*number"), "invalid input")
end
  1. assert returns the first parameter if it is true
  2. If the first parameter is false or nil, an error will be raised
  3. The second parameter is an optional information string
  4. Its parameters are evaluated when assert is called
  5. In the following code, Lua will connect strings even if n is a numeric type
n = io.read()
assert(tonumber(n), "invalid input:" .. n .. " is not a number")
  1. When a function encounters an unexpected situation, i.e. «exception», two basic behaviors can be taken

    1. Return error code (usually nil)
    2. Raise an error (call error)
  2. sin passes in table as a parameter

-- Return an error code, check sin Function return value
local res = math.sin(x)
if not res then
	<Error handling code>
end

-- call sin Before, check the parameters
if not tonumber(x) then
   	<Error handling code> 
end
  1. Usually neither the parameters nor the return value of sin are checked

  2. You can stop the calculation and give an error message

  3. Non existence of io.open file or abnormal behavior when access is denied

  4. Whether a file exists or not can be verified by whether it can be opened

  5. When io.open is unable to open a file, nil should be returned with an error message attached

do
    local file, msg
    repeat
        print("enter a file name:")
        local name = io.read()
        if not name then
            return
        end
        -- io.open The first parameter is the file path, and the second parameter is the open mode, r Is character mode
        -- io.open If it succeeds, the file handle will be returned. If it cannot be opened, the file handle will be returned nil And error messages
        file, msg = io.open(name, "r")
        if not file then
            print(msg)
        end
	until file
end

-- Equivalent to the above code.On error message io.open The second return value of, and becomes the assert Second parameter of
do
    local file, msg
    repeat
        print("enter a file name:")
        local name = io.read()
        if not name then
            return
        end
       file = assert(io.open(name, "r"))
	until file
end

Error handling and exceptions

  1. In most cases, you don’t need to do any error handling in Lua, which is the responsibility of the application calling Lua

  2. Because all Lua activities start with a single call from the application

    1. Lua is usually required to execute a block
    2. If an error occurs, the call returns the error code and is processed by the application
  3. When an error occurs in the interpreter program, the main loop prints the error message, then continues to display the prompt and waits for subsequent commands to be executed

  4. When handling errors in Lua, pcall must be used to wrap the code to be executed. P > means protect

  5. pcall can catch any errors raised when a function executes

    1. If there are no errors, it will return true and the return value of the function call
    2. If there is an error, it will return false and error message
-- Execute a paragraph Lua Code,To capture all errors in execution, you need to encapsulate this code into a function
function foo()
    <code block>
    if Unexpected conditions then 
        error()
    end
    <code block>
    print(a[i]) -- Potential errors, a Maybe not one table
    <code block>
end

if pcall(foo) then
    -- implement foo No error occurred at
    <Regular code>
else
    -- foo An error was raised for error handling
    <Error handling code>
end
  1. An anonymous function can be passed in when pcall is called

  2. The error message can be any value and is passed to the error function, which becomes the return value of pcall

if pcall (function ()
	-- <Protected code>        
    return 20 + 10 -- Code for testing "a" + 10
end) then
    -- <Regular code>
    print("ok")
else
    -- <Error handling code>
    print("error")
end

do
	local status, err = pcall(function ()
        error({code = 121})
 	end)
    print(status, err.code)
end
  1. A complete exception handling process in Lua is usually:
    1. Use error to throw an exception
    2. Use pcall to catch exceptions
    3. Error messages are used to identify the type or content of the error

Error messages and traceability

  1. An error message is usually a string that describes what went wrong
  2. Lua encounters an internal error, such as indexing a non table value, and an error message will be generated
  3. In other cases, the error message is the value passed to the error function
  4. As long as the error message is a string, Lua appends some information about where the error occurred
do
    local status, err = pcall(function () a ="a"+1 end)
    print(err)
end

do
    local status, err = pcall(function () 
            error("my 	error") 
    end)
    print(err)
end
-- Location information contains file name stdin And line number 3
-- stdin:3: my error
  1. The second parameter of the error function, level, indicates which function in the call level should report the current error, that is, who is responsible for the error
-- In a function, check at the beginning whether the passed in parameter is correct
do
    function foo(str)
        if type(str) ~= "string" then
            -- If the second parameter is not added, it is considered to be an error in reading the function and an error is reported, stdin:3: string expected
            -- error("string expected")
            -- With the second parameter, an error is considered at the call level and reported, stdin:9: string expected
            error("string expected", 2)
        end
        print(str)
    end

    foo({x = 1})
end

  1. When the pcall function returns an error message, it has destroyed part of the call stack

  2. If you want to get a complete trace back to the function call when the error occurs, rather than just get the location where the error occurred, you need to use the xpcall function

  3. The xpcall function takes two arguments

    1. Function to be called
    2. And an error handling function
  4. When an error occurs, Lua will call the error handling function before the call stack is expanded, and you can use the debug library to get the wrong additional information.

Two general processing functions of debug library

  1. debug.debug, which provides a Lua prompt for the user to check the cause of the error
  2. debug.traceback, build an extended error message based on the call stack
  3. The interpreter uses debug.traceback to build its error messages
  4. Any time you call debug.traceback, you can get the currently executed call stack
do
    local t = {2, 4, 6, 8 ,10}
    for i,v in ipairs(t) do
       	print(i, v)
        print(debug.traceback())
    end
end

This article is published by one article multiple platform ArtiPub Automatic publishing

Понравилась статья? Поделить с друзьями:
  • Lua error что это
  • Lua error unexpected symbol near
  • Lua error table index is nil
  • Lua error string serious sam
  • Lua error stdin 1 attempt to call field alarm a nil value