لوآ (زبان برنامه‌نویسی)

از ویکی‌پدیا، دانشنامهٔ آزاد
پرش به: ناوبری، جستجو
برای مطالب پیرامون استفادهٔ لوآ در ویکی‌پدیا، ویکی‌پدیا:لوآ را ببینید.

لوآ یک زبان برنامه‌سازی سبُک‌وزن، بازتابنده و امری-تابعی است. زبان لوا با ساختار پردازه‌نویسی (برنامه‌نویسی اسکریپتی) و با هدف داشتن قابلیت‌های گسترش‌پذیر طراحی شده است.

فلسفلهٔ اولیه ساخت این زبان، استفاده از آن به عنوان یک زبان عمومی و ساده پردازه‌نویسی بود. جامعه هدف لوا شامل کاربران نیمه حرفه‌ای هم می‌شود. در پردازه‌نویسی برای انجام توصیفات پیچیده از یک زبان نهفته شده در یک زبان دیگر استفاده می‌شود. به خاطر سبک بودن کتابخانه لوا، می‌توان لوا را با تمام قابلیت‌ها به عنوان یک زبان نهفته در سی استفاده نمود. حجم مفسر کامپایل شده حدود ۱۵۰KB است.

در طراحی لوا سعی شده است از فرا ساز و کارها بیشتر استفاده شود تا در عین کوچکی، انعطاف‌پذیری زبان افزایش یابد. داده‌ساختار جدول، داده ساختار اصلی مورد استفاده در این زبان است.

لوا یک مفسر اصلی دارد که توسط طراحان اصلی زبان پیاده‌سازی شده است. این مفسر دارای واسط سی نسبتاً سبک و ساده‌ای است.[۱]

هر دوی لوا و جاوااسکریپت از اشیاء نمونه‌پایه استفاده می‌کنند. آنها هر دو از شِما الگو گرفته‌اند. بسیاری از مفاهیم مشترک میان آن‌ها وجود دارد، گرچه تفاوت‌های اساسی در نحو دارند. در طراحی لوا شبیه به آیکون است، شاید به این علت که هر دو از اسنوبال تاثیر پذیرفته‌اند.

زبان لوا در طول زمان تغییر می‌کند، قابلیت‌هایی از آن کاسته و قابلیت‌هایی بر آن افزوده می‌شوند. اکنون این زبان در نسخه ۵.۱ قرار دارد (ژوئن ۲۰۰۹)

لوا در صنعت بازی‌های ویدیویی محبوبیت زیادی دارد. به جز بازی‌ها لوا در کاربردهای بسیاری هم تجاری و هم غیرتجاری استفاده شده است. نام این زبان از کلمه پرتغالی lua به معنای «ماه» می‌آید.

تاریخچه[ویرایش]

لوا در سال ۱۹۹۳ توسط روبرتو یروسالیمچی، لوییز هنریک دی فیگوئردو و والدمر سلس، اعضای تِکگِراف - گروه تکنولوژی گرافیک کامپیوتر (TecGraph) در PUC-Rio، دانشگاه مسیحی ریو دی جانیرو در برزیل ساخته شد.

از سال ۱۹۷۷ تا ۱۹۹۲ در برزیل قوانین سخت تجارت خارجی روی سخت‌افزار و نرم‌افزار وجود داشت. این قوانین از انگیزه ملی توانایی ساخت نرم‌افزار و سخت‌افزار در داخل برزیل نشات گرفته بود. این قوانین موجب شد که تکگراف نه از نظر اقتصادی و نه سیاسی امکان داشته باشد که بتواند نرم‌افزار آماده شده از خارج کشور خریداری کند. به جز این مساله، جدایی جغرافیای برزیل از بقیه مراکز تحقیقات و توسعه، موجب شد که تکگراف ابزارهایی که نیاز داشت را از هیچ تولید کند.

«پدر و مادر» تاریخی لوا زبان‌های توصیف داده/تنظیم (SOL (Simple Object Language و (DEL (Date Entry Language هستند. آن دو به طور مستقل در سال‌هال ۱۹۹۲-۱۹۹۳ در تکگراف تولید شده‌اند، تا دو پروژهٔ متفاوت را منعطف‌تر کنند (هر دوی این پروژه‌ها برنامه‌های گرافیکی تعاملی برای کاربردهای مهندسی در شرکت پتروبرس بودند.در SOL و DEL ساختارهای کنترلی وجود نداشت و نیاز به یک زبان برنامه‌سازی کامل‌تر احساس می‌شد. «در ۱۹۹۳ تنها رقیب اصلی لوا تیکل بود، که به طور صریح برای استفاده نهفته در برنامه‌ها طراحی شده بود. اما تیکل نحوی نا آشنا داشت، پشتیبانی کافی از توصیف داده نداشت و فقط روی محیط یونیکس قابل استفاده بود. ما لیسپ و شما را استفاده نکردیم چون نحو زشتی داشتند. پایتون هنوز در نوزادی به سر می‌برد.در جو آزاد و مستقل تکگراف تقریباً عادی بود که ما باید زبان پردازه‌نویسی خودمان را اختراع می‌کردیم... به این علت که خیلی از کاربران محتمل زیان برنامه‌نویسان حرفه‌ای نبودند، زبان باید از نحو و مفاهیم مرموز خودداری می‌کرد. پیاده‌سازی زبان جدید باید قابلیت اجرا روی محیط‌های مختلف را می‌داشت چون کاربران تکگراف انواع متمایزی رایانه در اختیار داشتند. در نهایت، از آنجه که ما انتظار داشتیم که محصولات دیگر تکگراف هم نیاز به نهفتن یک زبان پردازه‌نویسی داشتند، زبان جدید باید مثال SOL را ادامه می‌داد و به عنوان کتاب‌خانه‌ای همراه API سی ارائه می‌شد.» [۲]

در نتیجه لوا به دنیا آمد. سازنده‌های اشیا لوای ۱.۰ که آن زمان کمی متفاوت از حالت سبُک و انعطاف‌پذیر امروزی متفاوت بودند، نحو توصیف دادهٔ SOL را به کار گرفته بودند (ریشه نام لوا از همین‌جا می‌آید، sol در زبان پرتغالی یه معنای خورشید است و لوا به معنای خورشید). ساختارهای کنترلی لوا (if,while,repeat/until) بیشتر از مدولا قرض گرفته شده بودند، اما از CLU هم تاثیر گرفته است (مقدار خروجی چندگانه از توابع و عملیات مقداردهی چندگانه به عنوان گزینه‌ای ساده‌تر از پارامترهای ارجاعی یا اشاره‌گرهای صریح). لوا همچنین از ++C (تعریف محدودتر حوزه متغیرها)، آوک و سنوبال (آرایه‌های انجمنی) هم تاثیر گرفته است. در یک مقاله منتشر شده در مجله «Dr Dobb's Journal»، سازندگان لوا همچنین اذعان می‌کنند که زبان لیسپ و شما هم با داده ساختار تکین خود (لیست) تاثیر مهمی روی تصمیم سازندگان بر استفاده از جدول به عنوان داده ساختار اولیه داشتند. مفاهیم فعلی لوا بیشتر از شما گرفته شده‌اند: «از نظر مفهوم لوا شباهت‌های زیادی به شما دارد، گرچه این شباهت‌ها مستقیماً دیده نمی‌شوند، چون این دو زبان تفاوت‌های نحوی زیادی دارند. تاثیر شما روی لوا به تدریج در زمان تکامل لوا افزایش یافته است: در ابتدا شما فقط زبانی در پس‌زمینه بود اما بعداً به تدریج به عنوان منبعی برای ایده گرفتن مهم شد، به خصوص به خاطر معرفی توابع ناشناس و حوزه‌بندی کامل» [۳]

کاربردها[ویرایش]

لوا در صنعت بازی‌های ویدیویی محبوبیت زیادی دارد. در تعدادی از موتور های بازی از زبان لوا برای توسعه و به عنوان اسکریپت استفاده می شود از جمله :

از جملهٔ بازی‌هایی که از افزون‌بسته‌های (Plugin) لوا پشتیبانی می‌کنند می‌توان به موارد زیر اشاره کرد:

به جز بازی‌ها لوا در کاربردهای بسیاری هم تجاری و هم غیرتجاری استفاده شده است از جمله:

  • Adobe Photoshop Lightroom
  • Apache HTTP Server
  • Damn Small Linux
  • LuaTex
  • nmap
  • WireShark

ساختار کلی[ویرایش]

دستورات لوا خط به خط توسط مفسر اجرا می‌شوند. در لوا همچون زبان‌های پردازه‌نویسی دیگر تابع اصلی (main) وجود ندارد (می‌توان اینطور تصور کرد که کل برنامه یک تابع اصلی است). هر بلوک کد لوا یا مربوط به مقداردهای متغیر است یا اینکه اجرای یک تابع خاص می‌باشد. ارتباط با دنیای بیرون از طریق رابط برنامه‌نویسی نرم‌افزار انجام می‌شود. متغیرهایی که تعریف می‌شوند به دو دسته عمومی و محلی تقسیم می‌شوند. متغیرهای محلی متغیرهایی هستند که حوزه آنها یک تابع خاص است. در این زبان پیش‌پردازنده وجود ندارد. در لوا مستقیماً قابلیت‌های زیادی وجود ندارد، بلکه هر برنامه‌نویس با فرا ساز و کارهای تعبیه شده می‌تواند قابلیت لازم خود را اضافه کند. این فرا ساز و کارها عبارتند از: آرایه‌های انجمنی پویا (Dynamic Associative Arrays)، ابزارهای انعطاف‌پذیر (Reflexive Facilities) و فراجدول‌ها (Metatables)

کد نمونه[ویرایش]

کدهای این قسمت همگی کامل هستند و بدون هیچ تغییری تفسیر می‌شوند.

برنامهٔ نوشتن عبارت "Hello World" بر روی صفحه:

print('Hello World') -- this is a comment

کامنت‌ها با -- مشخص می‌شوند.

جمع کردن دو عدد در ورودی:

a = io.read()
b = io.read() 
print(a+b)

توصیف یک پنجره گرافیکی:

d = dialog { 
	hbox {
		button{ label = "ok" },
		button{ label = "cancel" }
	}
}

در این مثال dialog با یک جدول توصیف می‌شود.

تابع فاکتوریل نمونه‌ای از یک تابع بازگشی در لوا است، که به دو روش پیاده‌سازی شده است:

function factorial(n)
  if n == 0 then
    return 1
  else
    return n * factorial(n - 1)
  end
end 
 
function factorial2(n) -- Shorter equivalent of the above
  return n == 0 and 1 or n * factorial2(n - 1)
end

در تابع دوم از خصوصیت محاسبه کمینه عبارت بولی از چپ در زبان لوا استفاده شد. یعنی اینکه فقط اگر شرط n==0 برقرار نباشد محاسبه (factorial2(n-1 انجام می‌شود.

عوض کردن تابع print تعریف شده در لوا به گونه‌ای که رفتار آن فقط به ازای حالت خاص ورودی "foo" تفاوت کند.

do
  local oldprint = print           -- Store current print function as oldprint
  function print(s)                -- Redefine print function
    if s == foo" then
      oldprint("bar")
    else 
      oldprint(s) 
    end
  end
end

این مثال به خوبی نشان می‌دهد که توابع کتابخانه در لوا متغیرهای عمومی (یا سطح اول) هستند.

سیستم تایپ[ویرایش]

لوا پویندگی تایپ دارد، یعنی نوع متغیرها در لوا در زمان همگردانی مشخص نمی‌شود، بلکه هر متغیر در زمان اجرا نوعش تعیین می‌شود. در واقع در تعریف متغیر، نوع متغیر توسط برنامه‌نویس نوشته نمی‌شود. زمانی که برنامه‌نویس یک عمل مقداردهی به آن متغیر انجام می‌دهد، نوع متغیر بسته به چیزی که در متغیر ذخیره می‌شود تعیین می‌شود. نوع متغیرها می‌تواند در طول اجرا تغییر کند.

نوع داده‌های اولیه[ویرایش]

در لوا ۸ نوع داده اولیه وجود دارد:

  • نوع صحت (Boolean): مقدار true یا false می‌تواند بگیرد.
  • عدد: عددی اعشاری با دقت دوگانی (double precision)
  • رشته: رشته‌ای از کاراکترهای یک بایتی. از تمام کاراکترهای ۰ تا ۲۵۵ می‌توان در رشته استفاده کرد.
  • تابع: با هر تابع هم مثل یک متغیر برخورد می‌شود. برای آن متغیر عملگر )( تعریف شده است.
  • جدول: جدول ساختارداده‌ای شبیه آرایه است، اما می‌توان از هر تایپی (عدد، رشته، ...) برای اندیس‌گذاری در آن استفاده کرد.
  • ریسه: ساختار داده مربوط به همروند سازی اجرا
  • کاربرداده (userdata): برای پیوند میان لوا و C باید اشاره‌گرها را بتوان در لوا استفاده کرد. کاربرداده همین کار را می‌کند.
  • Nil: یک نوع خاص که فقط یک مقدار هم دارد که آن مقدار با nil مشخص می‌شود

جدول‌ها[ویرایش]

داده‌ساختار اولیه لوا، جدول است. جدول ساختارداده‌ای شبیه آرایه است، اما می‌توان از هر تایپی (عدد، رشته، ...) برای اندیس‌گذاری در آن استفاده کرد. مثلاً در کد زیر:

t = {}
t["mohsen"] = 1
t["ali"]=2
x = t["mohsen"] + t["ali"]
print(x) -- prints 3

با جای اندیس‌های عددی از اندیس "mohsen" و "ali" استفاده شده است. قبل از اینکه بتوان از عملگر [] استفاده کرد باید متغیر مربوطه را مقدار دهی اولیه به مقداری جدولی کرد. ساده‌ترین مقداردهی اولیه مقدار به {} دادن است. می‌توان از عبارات زیر هم استفاده کرد:

t = {mohsen = 1, ali = 2}

در کد بالا t مانند مثال قبلی مقداردهی می‌شود.

داده‌ساختار جدول (از دید برنامه‌نویس) شبیه جدولی است که دو ستون دارد: در ستون اول تعدادی صفت مشخص شده است (مثلاً رنگ، اندازه، ...). در ستون دوم جلوی هر سطر مقدار متناظر آن صفت آمده است. مثلاً روبروی سطر رنگ آمده است آبی. برنامه‌نویس می‌تواند یک سطر به جدول اضافه کند، یک سطر را حذف کند یا مقدار ستون دوم یک سطر را تغییر دهد. همهٔ این اعمال با این نحو انجام می‌شود:

t[x] = a

که در آن t یک جدول است و x نام ستون است. اگر x مقداری بوده که قبلاً هم در جدول بوده (در ستون اول)، آنگاه مقدار روبروی آن x می‌شود. در حالت خاصی که a برابر nil باشد آن ستون حذف می‌شود. اگر x قبلاً در جدول نبوده آنگاه یک سطر جدید اضافه می‌شود که در ستون اول آن x و در ستون دوم a آمده است. پس یک جدول یک رشته را به یک مقدار متناظر می‌کند.

از جدول برای پیاده‌سازی مفاهیم مختلفی استفاده می‌شود: آرایه، شی و فضای نام

جدول به عنوان آرایه[ویرایش]

در مثال زیر:

colors1 = {"blue", "green"}
colors2[1] = "blue"
colors2[2] = "green"

مقداردهی colors1 از نوع جدیدی است که با مقداردهی colors2 معادل است. به این ترتیب یک جدول که اندیس‌هایش اعداد صچحیح ۱ تا n هستند می‌تواند بیانگر مفهوم یک آرایه یاشد.

جدول به عنوان داده ساختار شی[ویرایش]

هر شی را می‌توان با یک جدول نمایش داده. مثلاً اگر می‌خواهیم اتاقی را توصیف کنیم، می‌توان از کد زیر استفاده کرد:

room = {color="blue",x=10,y=20}

در این مثال صفت هایی که برای توصیف به کار رفته‌اند، عبارتند از طول و عرض اتاق (x و y) و رنگ (color).

لوا از تایپ‌دهی اردکی استفاده می‌کند. کلاس‌ها در لوا تعریف نمی‌شوند، فقط نمونه‌ها از اشیا تعریف می‌شوند. در تعریف هرنمونه باید تمامی صفات را معین کرد. وفتی روی هر نمونه‌ای عملیات انجام می‌شود، درجا امکان انجام عملیات بررسی می‌شود. اگر این امکان نباشد خطای زمان اجرا پیش می‌آید (البته می‌توان با فراجدول‌ها بعضی از این خطاها را مهار کرد) پس در صورتی که نمونه‌ای خصوصیات کافی داشته باشد، از نظر مفهومی به عنوان یک نمونه از یک کلاس خاص محسوب می‌شود.

برای سادگی لوا یک نحو ویژه برای اینگونه استفاده از جدول ایجاد کرده است. با نوشتن room.x در مثال بالا به مقدار x دست می‌یابیم، دقیقاً مانند اینکه نوشته باشیم room["x"]. این نمایش مفهوم شیء را می‌رساند و به کسانی که با نحو object.attribute عادت دارند هم کمک می‌کنند.

ساز و کار تولید مثل[ویرایش]

برای ساده‌سازی فرایند نمونه‌سازی لوا از ساز و کار تولید مثل استفاده می‌کند. در این ساز و کار، یک نمونه ساخته می‌شود و سپس از تابعی کمکی استفاده می‌شود تا مانند آن نمونه به تعداد کافی ساخته شود. این تابع به صورت زیر قابل پیاده‌سازی است.

function clone(o)
	local new_o = {}
	local i,v = next(o,nil)
	while i do
		new_o[i] = v
		i, v = next(o, i)
	end
	return new_o
end

در این مثال از ابزارهای انعطاف پذبر استفاده شده است.

جدول به عنوان نام فضای نام[ویرایش]

با استفاده از یک جدول می‌توان توابع مرتبط را در یک فضا نگهداری کرد:

Point = {}
Point.new = function (x, y)
  return {x = x, y = y}
end
 
Point.set_x = function (point, x)
  point.x = x
end

ابزارهای انعطاف پذیر[ویرایش]

در لوا می‌توان روی عناصر یک جدول حرکت کرد. برای این منظور از تابع next استفاده می‌شود. این تابع یک متغیر می‌گیرد و اولین عضو بعد از آن در جدول را برمی‌گرداند (توجه کنید که اعضا در جدول با ترتیبی تعریف نشده نگهداری می‌شوند). next(nil) اولین عضو جدول را برمی‌گرداند. این قابلیت به لوا امکانات زیادی می‌دهد از جمله تولید مثل اشیا یا ذخیره‌سازی و بازیابی تمام متغیرهای عمومی.

حوزه متغیرها[ویرایش]

حوزه متغیرها در لوا دو حالت دارد: عمومی و محلی. متغیرهای محلی با عبارت local در ابتدای آنها مشخص می‌شوند. متغیرهای عمومی در همه جا قابل دسترسی هستند اما متغیرهای محلی فقط در بدنه همان تابع یا توابع تعریف شده در درون آن تابع قابل دسترسی هستند. مثال زیر به خوبی حوزه متغیرها را نشان می‌دهد. در تابع print به جای مقادیری که در حوزه نیستند nil چاپ می‌شود.

y = 1
function f(x) 
	y = 2
	local z = 3
	local function g(r) 
		z = 4
	end
	g(z)
	return z
end
 
print(f(x)) -- prints 4
print(y) -- prints 2
print(z) -- prints nil

فراجدول‌ها[ویرایش]

لوا دارای سیستم تایپ پویا می‌باشد. بنابراین در زمان اجرا مشخص می‌شود که انجام یک عمل خاص ممکن است یا نه. مثلاً در کد زیر

a1 = {x=1,y=2}
a2 = {x=3,y=4}
c = a1 + a2

وقتی که کد مربوط به c=a+b تفسیر می‌شود امکان ناپذیر بودن آن مشخص می‌شود. برای اینکه احاطه برنامه‌نویس بر روند اجرا بیشتر شود، قابلیت فراجدول به زبان اضافه شد. این قابلیت اجازه می‌دهد که به جای رخ دادن خطاهای زمان اجرا تابعی از پیش تعیین شده توسط کاربر اجرا شود. این تابع وضعیت خطا را بررسی می‌کند و می‌تواند هم فعالیتی را در این زمان انجام دهد (مثلاً ضبط این موضوع که خطا رخ داده در یک فایل) یا اینکه یک مفهوم جدید برای عمل تعریف نشده تعریف کند. در مثال بالا جمع دو جدول را اینگونه تعریف کرد که مقادیر متناظر نام‌های یکسان را جمع می‌کنیم (اگر مقداری در جدول اول بود که متناظری در جدول دوم نداشت حاصل nil می‌شود). کد این فراجدول اینگونه است:

mt = { __add = function (a, b)
			local ret={}
			local i=next(a,nil)
			while i do
				v = a[i]
				if b[i]==nil then
					return nil
				end
				v_p = b[i]
				e, r = pcall(function() return v + v_p end)
				if e then
					ret[i] = r
				else
					return nil
				end
				i = next(a,i)
			end 
		return ret;
	end
}
a1 = {x=1,y=2}
a2 = {x=3,y=4}
setmetatable(a1,mt)
c = a1 + a2
print(c.x,c.y)

این کد در lua نسخه ۵.۱ به قبل قابل ترجمه نیست چون آن زمان به جای فراجدول‌ها ساز و کار مشابهی به نام عقب‌گردان‌ها (Fallbacks) وچود داشت. عقب‌گردان‌ها به علت مشکلاتی که در خوانایی و قابلیت نگهداری و استفاده دوباره کد ایجاد می‌کردند از نسخه ۳.۰ به بعد از زبان حذف شدند.

برنامه نویسی شیءگرا[ویرایش]

شیءگرایی در لوا به طور مستقیم وارد نشده است. شیءگرایی از طریق ساز و کار فراجدول‌ها قابل پیاده‌سازی است. نمونه‌ای ساده از پیاده‌سازی شیءگرایی:

a={x=100, y=200, color="red"}
b={x=300, y=400}
setmetatable(b,{ __index = a })
print(b.color) --> red

رابط برنامه‌نویسی نرم‌افزار (API)[ویرایش]

زبان‌های پردازه‌نویسی درون یک زبان بزرگتر اجرا می‌شوند. این زبان باید با زبان پردازه‌نویسی داخلی از طریق یک لایه ارتباط برقرار کند، که آن رابط ربن(برنامه‌نویسی نرم‌افزار) است. در لوا از دو بخش هسته و کمکی تشکیل شده است. لایه ربن در لوا نسبتاً ساده است، چون برخلاف پایتون مدیریت ارجاع در آن نیاز نیست. ربن لوا همچون خود زبان کمینه است: عملکرد پیشرفته‌تر توسط کتاب‌خانهٔ کمکی پشتیبانی می‌شود، که شامل ماکروهای تعریف شده زیادی است که عملیات پیچیده جدولی را آسان می‌کند.

یادداشت‌ها[ویرایش]

  1. ^  پایگاه وب مفسر اصلی ریو
  2. ^  اضافه‌شونده‌های لوا

منابع[ویرایش]

  1. Ierusalimschy et al., "Lua -- an extensible extension language", TeCGraf, Computer Science Department, PUC-Rio, 1995
  2. Ierusalimschy et al., "Lua 5.1 Reference Manual", 2006-2008 Lua.org, PUC-Rio
  3. "Metamethods Tutorial", lua-users wiki
  4. Ierusalimschy et al., "The Evolution of Lua", Proceedings of the Third ACM SIGPLAN History of Programming Languages Conference, 2007