1. تعارف

Expr ایک متحرک تشکیل کا حل ہے جو Go زبان کے لیے تیار کیا گیا ہے، جس کی سادہ سکیواکس اور طاقتور کارکردگی کی خصوصیتوں کی وجہ سے مشہور ہے. Expr کا اصل انجن بےخوفی، رفتار اور عقلمندی پر مبنی ہے، جو اسے رسائی کنترول، ڈیٹا فلٹرنگ اور وسائل کا منظور بناتا ہے۔ جب یہ Go میں استعمال ہوتا ہے، تو Expr کو اہمیت حاصل ہوتی ہے کے تقاضوں کو حق کرنے کی صلاحیت فراہم کرتا ہے۔ دوسری زبانوں کی مقابلے میں ترجمانوں یا اسکرپٹ انجنوں کے برعکس، Expr سٹیٹک ٹائپ چیکنگ استعمال کرتا ہے اور حقیقت میں بائٹ کوڈ بناتا ہے تاکہ اسکی کارکردگی اور حفاظت دونوں یقینی بنائی جا سکے۔

2. Expr کی تنصیب

Go زبان کی پیکج منیجمنٹ ٹول go get کا استعمال کرتے ہوئے آپ Expr ایکسپریشن انجن کو تنصیب کرسکتے ہیں:

go get github.com/expr-lang/expr

یہ کمانڈ Expr کتب خانے کے فائلیں ڈاؤن لوڈ کرے گی اور انہیں آپ کے Go منصوبے میں انسٹال کرے گی، جس سے آپ اپنے Go کوڈ میں Expr کو import اور استعمال کرسکتے ہیں۔

3. تیز رفتار شروع

3.1 بنیادی ایکسپریشنز کو کمپائل اور چلانا

آئیے ایک بنیادی مثال سے شروع کریں: ایک سادہ ایکسپریشن لکھیں، اسے کمپائل کریں اور پھر نتیجہ حاصل کرنے کے لیے اسے چلائیں۔

package main

import (
	"fmt"
	"github.com/expr-lang/expr"
)

func main() {
	// سادہ اضافہ ایکسپریشن کو کمپائل کرنا
	program, err := expr.Compile(`2 + 2`)
	if err != nil {
		panic(err)
	}

	// متغیر کی ضرورت نہیں ہونے کی بنا پر محیط کو گزرانے بغیر کمپائل شدہ ایکسپریشن کو چلانا
	output, err := expr.Run(program, nil)
	if err != nil {
		panic(err)
	}

	// نتیجہ چھاپنا
	fmt.Println(output)  // 4 آؤٹ پٹ
}

اس مثال میں، ایکسپریشن 2 + 2 کو قابل اجراء بائٹ کوڈ میں کمپائل کیا گیا ہے، جس کو پھر نتیجہ حاصل کرنے کے لیے استعمال کیا گیا ہے۔

3.2 متغیر ایکسپریشنز کا استعمال کرنا

اگلے، ہم ایک محیط بنائیں گے جو متغیرات پر مشتمل ہوتا ہے، ایک ایسی ایکسپریشن لکھیں گے جو ان متغیرات کو استعمال کرتی ہے، اور اس ایکسپریشن کو کمپائل اور آئیں رن کریں گے۔

package main

import (
	"fmt"
	"github.com/expr-lang/expr"
)

func main() {
	// متغیرات سے یکائی محیط تشکیل دینا
	env := map[string]interface{}{
		"foo": 100,
		"bar": 200,
	}

	// متغیرات کو استعمال کرنے والی ایکسپریشن چکپش کرنے والا ایکسپریشن کمپائل کرنا
	program, err := expr.Compile(`foo + bar`, expr.Env(env))
	if err != nil {
		panic(err)
	}

	// ایکسپریشن کو چلانا
	output, err := expr.Run(program, env)
	if err != nil {
		panic(err)
	}

	// نتیجہ چھاپنا
	fmt.Println(output)  // 300 آؤٹ پٹ
}

اس مثال میں، محیط env میں متغیرات foo اور bar شامل ہیں۔ ایکسپریشن foo + bar کمپائल کی تشخیص کے دوران foo اور bar کی قسمیں محیط سے انفر کرتی ہیں، اور ان متغیرات کی قیمتوں کا استعمال کر کے اس کا نتیجہ حاصل کیا جاتا ہے۔

4. Expr کا تفصیلی سکوپ

4.1 متغیرات اور حقیقیات

Expr ایکسپریشن انجن عام ڈیٹا ٹائپ حقیقت، شماریاتی شماریات اور بولین قیمتوں کا سامنا کر سکتا ہے۔ حقیقیات وہ ڈیٹا قیمتیں ہیں جو کوڈ میں مستقیم طور پر لکھی گئی ہوں، جیسے 42،"hello"، اور true۔

اعداد

Expr میں آپ سیدھے اور اور فلوٹنگ پوائنٹ نمبرز لکھ سکتے ہیں:

42      // سیدھا 42 کا عدد ہے
3.14    // 3.14 کا فلوٹنگ پوائنٹ نمبر ہے

رشتے

رشتے دو قوتوں " " یا backticks ` میں نقل کرے جاتے ہیں۔ مثال کے طور پر:

"hello, world" // رشتہ علیہ حنظلہ میں نقل
`hello, world` //رشتہ backticks میں نقل، حمّلے کرنے والے کردار کے بغیر رشتہ کو برقرار رکھتا ہے

بولین

صرف دو بولین قیمتیں ہیں، true اور false، جو منطقی سچ اور جھوٹ کو ظاہر کرتے ہیں:

true   // بولین سچی قیمت
false  // بولین جھوٹی قیمت

متغیرات

Expr متغیرات کی تعریف محیط میں بھی ممکن بناتا ہے، اور پھر ان متغیرات کو ایکسپریشن میں حوالہ دیا جا سکتا ہے۔ مثال کے طور پر:

env := map[string]interface{}{
    "age": 25,
    "name": "Alice",
}

پھر ایکسپریشن میں آپ age اور name کا حوالہ دے سکتے ہیں:

age > 18  // چیک کریں کہ عمر 18 سے زیادہ ہے یا نہیں
name == "Alice"  // یہ تصدیق کریں کہ نام "Alice" کے برابر ہے یا نہیں

4.2 اپریٹرز

Expr ایکسپریشن انجن مختلف اوپریٹرز کی حمایت کرتا ہے، جن میں حسابی اوپریٹرز، منطقی اوپریٹرز، موازنہ اوپریٹرز، اور سیٹ اوپریٹرز شامل ہیں۔

حسابی اور منطقی آپریٹرز

حسابی آپریٹرز میں جمع (+)، منفی (-)، ضرب (*)، تقسیم (/)، اور باقی حاصل (%) شامل ہیں۔ منطقی آپریٹرز میں منطقی AND (&&)، منطقی OR (||)، اور منطقی NOT (!) شامل ہیں، مثلاً:

2 + 2 // نتیجہ 4 ہے
7 % 3 // نتیجہ 1 ہے
!true // نتیجہ false ہے
age >= 18 && name == "Alice" // جانچیں کہ عمر 18 سے کم نہیں ہے اور نام "Alice" کے برابر ہے

موازنہ کرنے والے آپریٹرز

موازنہ کرنے والے آپریٹرز میں برابری کا (==)، برابر نہیں ہونا (!=)، کم ہے (<)، کم یا برابر ہے (<=)، زیادہ ہے (>)، اور زیادہ یا برابر ہے (>=) شامل ہیں، جو دو قیمتوں کا موازنہ کرنے کے لئے استعمال ہوتے ہیں۔

age == 25 // جانچیں کہ عمر 25 کے برابر ہے
age != 18 // جانچیں کہ عمر 18 کے برابر نہیں ہے
age > 20  // جانچیں کہ عمر 20 سے زیادہ ہے

سیٹ آپریٹرز

Expr میں چند آپریٹرز ہیں جو سیٹس کے ساتھ کام کرنے کے لئے ہیں، جیسے in جو چیز کو چیک کرنے کے لئے ہے کہ وہ سیٹ میں ہے یا نہیں۔ سیٹس عموماً arrays، slices، یا maps ہوتے ہیں۔

"user" in ["user", "admin"]  // ٹھیک ہے، کیونکہ "user" اس ایرے میں ہے
3 in {1: true, 2: false}     // ٹھیک نہیں ہے، کیونکہ 3 میں کوئی کلید نہیں ہے

ایسے بھی کچھ انتہائی پیشرفتہ سیٹ آپریٹر فنکشنز ہیں، جیسے all، any، one، اور none، جن میں غیر نامی فنکشنز (لیمبڈا) کا استعمال ہوتا ہے۔

all(tweets, {.Len <= 240})  // جانچیں کہ تمام ٹویٹس کی لنگت 240 سے زائد نہیں ہے
any(tweets, {.Len > 200})   // جانچیں کہ کیا ٹویٹس میں ایسی لنگت کی کوئی فیلڈ ہے جو 200 سے زیادہ ہے

ممبر آپریٹر

Expr ایکسپریشن زبان میں، ممبر آپریٹر ہمیں Go زبان میں struct کی خصوصیات تک رسائی فراہم کرتا ہے۔ یہ خصوصیت Expr کو پیچیدہ ڈیٹا ساختوں کو سیدھے طریقے سے منظم کرنے کی ایک بہت موزوں بناتی ہے۔

ممبر آپریٹر استعمال کرنا بہت آسان ہے، بس پراپرٹی کے نام کے بعد . آپریٹر استعمال کریں۔ مثلاً، اگر ہمارے پاس مندرجہ ذیل struct ہو:

type User struct {
    Name string
    Age  int
}

تو آپ User ساختہ کی Name پراپرٹی تک رسائی حاصل کرنے کے لئے نیچے لکھ سکتے ہیں:

env := map[string]interface{}{
    "user": User{Name: "Alice", Age: 25},
}

code := `user.Name`

program, err := expr.Compile(code, expr.Env(env))
if err != nil {
    panic(err)
}

output, err := expr.Run(program, env)
if err != nil {
    panic(err)
}

fmt.Println(output) // Output: Alice

nil قیمتوں کا سنبھالنا

پراپرٹیز تک رسائی کرتے وقت، آپ کو ایسی صورتوں میں بھی آ سکتا ہے جہاں آبجیکٹ nil ہو۔ Expr سیف پراپرٹی رسائی فراہم کرتا ہے، تو چاہے آبجیکٹ یا اسکے نسٹڈ پراپرٹی nil ہوں یا نہیں، یہ رن ٹائم پینک خرابی نہیں پیدا کرتا۔

پراپرٹیس کا حوالہ دینے کے لئے ?. آپریٹر کا استعمال کریں۔ اگر آبجیکٹ nil ہو، تو یہ خود بھی nil لوٹائے گا بجائے کے کہ خرابی پیدا کرے۔

author.User?.Name

مترادف ایکسپریشن

author.User != nil ? author.User.Name : nil

?? آپریٹر کا استعمال عموماً دیفالٹ قیمتیں لوٹانے کے لئے ہوتا ہے:

author.User?.Name ?? "Anonymous"

مترادف ایکسپریشن

author.User != nil ? author.User.Name : "Anonymous"

پائپ آپریٹر

Expr میں پائپ آپریٹر (|) ایک ایکسپریشن کے نتیجے کو دوسرے ایکسپریشن کے پیرامیٹر کے طور پر استعمال کرنے کے لئے استعمال ہوتا ہے۔ یہ یونکس شیل میں پائپ عمل کے ساتھ مشابہت رکھتا ہے، جو مکمل کرنے کے لئے متعدد فنکشنل ماڈیولز کو ایک ساتھ منسلک کرنے کا ایک پروسیسنگ پائپ لائن بناتا ہے۔ Expr میں اس کا استعمال کرتے ہوئے ہم بہتر اور مختصر ایکسپریشنز بنا سکتے ہیں۔

مثال کے طور پر، اگر ہمیں ایک صارف کا نام حاصل کرنے کا فنکشن اور خوش آمدید پیغام کے لئے ایک ٹیمپلیٹ ہو:

env := map[string]interface{}{
    "user":      User{Name: "Bob", Age: 30},
    "get_name":  func(u User) string { return u.Name },
    "greet_msg": "Hello, %s!",
}

code := `get_name(user) | sprintf(greet_msg)`

program, err := expr.Compile(code, expr.Env(env))
if err != nil {
    panic(err)
}

output, err := expr.Run(program, env)
if err != nil {
    panic(err)
}

fmt.Println(output) // نتیجہ: Hello, Bob!

اس مثال میں، ہم پہلے get_name(user) کے ذریعے صارف کا نام حاصل کرتے ہیں، پھر پائپ آپریٹر | کا استعمال کرتے ہوئے نام کو sprintf فنکشن کو منسلک کرتے ہیں تاکہ آخری خوش آمدید پیغام بنایا جا سکے۔

پائپ آپریٹر کا استعمال ہمارے کوڈ کو ماڈیولار بناتا ہے، کوڈ قابل دوبارہ استعمال بناتا ہے، اور ایکسپریشنز کو زیادہ قابل پڑھنے بناتا ہے۔

4.3 فنکشنز

Expr بلٹ-این فنکشنز اور خود سے بنائی گئی فنکشنز کو سپورٹ کرتا ہے، جو ایکسپریشنز کو زیادہ طاقتور اور لچکدار بناتا ہے۔

بلٹ-این فنکشنز کا استعمال

len، all، none، any وغیرہ جیسے بلٹ-این فنکشنز کو ایکسپریشنز میں سیدھے طور پر استعمال کیا جا سکتا ہے۔

// بلٹ-این فنکشن کا استعمال کا مثال
program, err := expr.Compile(`all(users, {.Age >= 18})`, expr.Env(env))
if err != nil {
    panic(err)
}

// نوٹ: یہاں env میں یوزرز متغیر شامل ہونا چاہئے، اور ہر صارف کا عمر پراپرٹی ہونی چاہئے
output, err := expr.Run(program, env)
fmt.Print(output) // اگر env میں تمام صارف عمر 18 سال یا اس سے زیادہ ہوں، تو یہ سچ ہو گا

خود سے بنائے گئے فنکشن کی تعریف اور استعمال

Expr میں، آپ فنکشن کی تعریفات کو ماپنگ میں پاس کر کے خود سے بنائی گئی فنکشنز بنا سکتے ہیں۔

// خود سے بنائے گئے فنکشن کا مثال
env := map[string]interface{}{
    "greet": func(name string) string {
        return fmt.Sprintf("Hello, %s!", name)
    },
}

program, err := expr.Compile(`greet("World")`, expr.Env(env))
if err != nil {
    panic(err)
}

output, err := expr.Run(program, env)
fmt.Print(output) // نتیجہ: Hello, World!

Expr میں فنکشنز کا استعمال کرتے وقت، آپ اپنے کوڈ کو ماڈیولر بنا سکتے ہیں، اور ایکسپریشنز میں پیچیدہ منطق کو شامل کر سکتے ہیں۔ متغیرات، آپریٹرز، اور فنکشنز کو یکجا کرکے، Expr ایک طاقتور اور آسان استعمال ہونے والا ٹول بن جاتا ہے۔ یاد رہے کے Expr ماحول کو بناتے وقت اور ایکسپریشنز کو چلاتے وقت ہمیشہ ٹائپ امنیت کی اطمینان دینا ضروری ہے۔

5. بلٹ-این فنکشن دستاویزات

Expr ایکسپریشن انجن ڈویلپرز کو مختلف پیچیدہ مواقع کے لئے بہترین بلٹ-این فنکشنز کا ایک واضح سیٹ فراہم کرتا ہے۔ نیچے، ہم ان بلٹ-این فنکشنز اور ان کا استعمال وضاحت کریں گے۔

all

all فنکشن کا استعمال اس کونین کی تمام عناصر پر چیک کرنے کے لئے ہوتا ہے کہ کیا ایک دی گئی شرط پر پورا اترتی ہیں یا نہیں۔ اس کا ایکسپریشن اور شرط مسلسل دو پیرامیٹرز لیتا ہے۔

// چیک کرنا کہ کیا تمام ٹویٹس کا مواد کم سے کم 240 حروف کا ہے یا نہیں
code := `all(tweets, len(.Content) < 240)`

any

any، all کے مشابہ ہے، لیکن یہ چیک کرتا ہے کہ کیا کوئی بھی کلیکشن میں عنصروں کا مفروضی شرط پورا کرتا ہے یا نہیں۔

// چیک کرنا کہ کیا کوئی ٹویٹ 240 حروف سے زیادہ کے ہے یا نہیں
code := `any(tweets, len(.Content) > 240)`

none

none، کلیکشن میں کوئی بھی عنصر شرط پر پورا کرتا ہے یا نہیں چیک کرنے کے لئے استعمال ہوتا ہے۔

// یہ دیکھنا کہ کیا کوئی ٹویٹ ریپیٹ نہیں ہے
code := `none(tweets, .IsRepeated)`

one

one فنکشن، یہ تصدیق کرتا ہے کہ کیا صرف ایک عنصر ٹائپ کونین کی شرط پر پورا کرتا ہے یا نہیں۔

// دیکھنا کہ کیا صرف ایک ٹویٹ میں مخصوص لفظ موجود ہے یا نہیں
code := `one(tweets, contains(.Content, "keyword"))`

filter

filter فنکشن کوئلیکشن کے عناصر کو فراہم شرط پر پورا کرنے والے عناصروں کو فلٹر کرتا ہے۔

// ہم قابلِ توجہ تویٹس کو فلٹر کرتے ہیں
code := `filter(tweets, .IsPriority)`

map

map فنکشن کوئلیکشن کے عناصر کو دی گئی ترکیب کے مطابق تبدیل کرنے کے لئے استعمال ہوتا ہے۔

// سب تویٹس کے پبلش ٹائم کو فارمیٹ کرتے ہیں
code := `map(tweets, {.PublishTime: Format(.Date)})`

len

len فنکشن کا استعمال کسی کلیکشن یا سٹرنگ کی لمبائی واپس کرنے کے لئے کیا جاتا ہے۔

// صارف کے نام کی لمبائی حاصل کرنا
code := `len(username)`

contains

contains فنکشن کا استعمال ہوتا ہے کہ کسی سٹرنگ میں کوئی ذیلی سٹرنگ موجود ہے یا اگر کسی کلیکشن میں کوئی خاص ارکان موجود ہیں یا نہیں ہیں۔

// چیک کرنا کہ کیا صارف کا نام غیر قانونی حروف شامل ہیں یا نہیں
code := `contains(username, "illegal characters")`

پیش کی گئی چیزیں صرف Expr ایکسپریشن انجن کی فراہم کردہ مضمون میں سے ایک حصہ ہیں۔ ان قوت مختصر فنکشنز کے ساتھ، آپ ڈیٹا اور منطق کو زیادہ چابک اور مؤثر طریقے سے ہینڈل کرسکتے ہیں۔ تفصیلی فنکشنز کی فہرست اور استعمال کی ہدایات کے لئے، براہ کرم رسمی Expr دستاویزات کا مطالعہ کریں۔