Implementasi VendisScript di Python

Post on 08-Jun-2015

193 views 0 download

Tags:

description

VendisScript's emulator implementation in Python. Describes how to implement a simple scripting language such as VendisScript in Python.

Transcript of Implementasi VendisScript di Python

Implementasi VendisScriptdi Python

Oleh: Irsyad Asyhari Lubis

Apa itu VendisScript?

is a scripting language

A scripting language or script language is a programming language that supports the writing of scripts, programs written for a special runtime environment that can interpret and automate the execution of tasks which could alternatively be

executed one-by-one by a human operator.

Sumber: http://en.wikipedia.org/wiki/Scripting_language

Typically, a scripting language is characterized by the following properties:

● Ease of use. ● OS facilities - especially filesystem and related,

built in with easy interfaces. ● Interpreted from source code - to give the

fastest turnaround from script to execution. ● Relatively loose structure.

Sumber: http://en.wikipedia.org/wiki/Scripting_language

Typically, a scripting language is characterized by the following properties:

● Ease of use. ● OS facilities - especially filesystem and related,

built in with easy interfaces. ● Interpreted from source code - to give the

fastest turnaround from script to execution. ● Relatively loose structure.

Sumber: http://en.wikipedia.org/wiki/Scripting_language

is interpreted scripting language

An interpreted language is a programming language that avoids explicit program compilation. The interpreter executes the program source code directly, statement by statement, as a processor or scripting engine does. This can be contrasted

with compiled language programs, which the user must explicitly translate into a lower-level machine

language executable.

Sumber: http://en.wikipedia.org/wiki/Interpreted_language

is embedded, interpreted scripting language

sorry, no reference this time...

used in Android based mobile sales and distribution software

why not Python?

compared to Python, VendisScript is...

simple

in term of implementation

too simple...

no optimization

no optimization (yet)

but, there is one reason to rule them all

size

it does matter!

less why...

more how...

now we are talking about implementation

in Python

note that...

scripting language on top of Python is generally not necessary

unless it is DSL

since this is only emulator...

Apa itu VendisScript?

JSON + Lisp

JSON

{    "firstName": "John",    "lastName": "Smith",    "age": 25,    "address": {        "streetAddress": "21 2nd Street",        "city": "New York",        "state": "NY",        "postalCode": 10021    },    "phoneNumbers": [        {            "type": "home",            "number": "212 555­1234"        },        {            "type": "fax",            "number": "646 555­4567"        }    ]}

Sumber: http://en.wikipedia.org/wiki/JSON

Lisp

(defun factorial (n)   (if (<= n 1)       1       (* n (factorial (­ n 1)))))

Sumber: https://en.wikipedia.org/wiki/Lisp_(programming_language)

Basic syntax

[

{

  "d": "Gratis 5 produk A untuk setiap pembelian 100 produk A.",

  "i": ["and",

         ["has", "11112313", "@products"],

         [">=", 

           ["bulk­qty", ["take", "11112313", "@products"]], 

           100.0]],

  "o": ["setq", "bonuses",

         ["add­bonus",

           ["bonus­new", "11112313",

             ["floatp", ["*", ["intp", 

               ["/", ["bulk­qty", ["take", "11112313", "@products"]], 100.0]], 5]], 

             "PCS"], 

             "@bonuses"]]

}]

[

{

  "d": "Gratis 5 produk A untuk setiap pembelian 100 produk A.",

  "i": ["and",

         ["has", "11112313", "@products"],

         [">=", 

           ["bulk­qty", ["take", "11112313", "@products"]], 

           100.0]],

  "o": ["setq", "bonuses",

         ["add­bonus",

           ["bonus­new", "11112313",

             ["floatp", ["*", ["intp", 

               ["/", ["bulk­qty", ["take", "11112313", "@products"]], 100.0]], 5]], 

             "PCS"], 

             "@bonuses"]]

}]

{

"d": "Test factorial.",

"i": true,

"o": ["prog",

["setq", "fac", 

["lambda", ["x"],

["cond",

["<=", "@x", 1], 1,

true, ["*", ["fac", ["­", "@x", 1]], "@x"]]]],

["fac", 3]]}

{

"d": "Test factorial.",

"i": true,

"o": ["prog",

["setq", "fac", 

["lambda", ["x"],

["cond",

["<=", "@x", 1], 1,

true, ["*", ["fac", ["­", "@x", 1]], "@x"]]]],

["fac", 3]]}

def fac(x):if x <= 1:

return 1else:

return x * fac(x ­ 1) 

[{

“d”: @description(str),“i”: @input(JSON),“o”: @output(JSON)

},...

]

Demo

Compiler Stack

SourceCode Lexer Parser AST

TargetCode

Grammar

prog : ('[' item (',' item)* ']' | '[' ']') EOF;

item : '{' '"d"' ':' QUOTED_IDENTIFIER ',' '"i"' ':' expr ',' '"o"' ':' expr '}';

expr :     | lambda_expr     | let_expr     | setq_expr     | prog_expr     | cond_expr     | apply_expr     | QUOTED_IDENTIFIER     | VAR_ACCESS     | '#nil'     | INT     | FLOAT     | 'true'     | 'false'     ;

lambda_expr : '[' '"lambda"' ',' '[' params ']' ',' body ']';

params : QUOTED_IDENTIFIER (',' QUOTED_IDENTIFIER)*;

body : expr ;

let_expr : '[' '"let"' ',' '[' init_list* ']' ',' body ']';

setq_expr : '[' '"setq"' ',' QUOTED_IDENTIFIER ',' expr ']';

init_list : '[' QUOTED_IDENTIFIER ',' expr ']';

prog_expr : '[' '"prog"' (',' expr)+ ']';

cond_expr : '[' '"cond"' (',' cond_and_expr)+ ']';

cond_and_expr : expr ',' expr;

apply_expr : '[' QUOTED_IDENTIFIER (',' expr)* ']';

VAR_ACCESS : '"@' IDENTIFIER '"';

QUOTED_IDENTIFIER : '"' IDENTIFIER '"';

INT : '­'? INT_WITHOUT_PREFIX;FLOAT : '­'? INT_WITHOUT_PREFIX '.' [0­9]* EXP?;

WS : [ \t\n\r]+ ­> skip;

fragmentIDENTIFIER : (ESC | ~('"'|'\\'))*;

fragmentINT_WITHOUT_PREFIX : '0'|[1­9][0­9]*;

fragmentEXP : [Ee][+|­]? INT_WITHOUT_PREFIX;

fragmentESC : '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\\'|UNICODE);

fragmentUNICODE : 'u' HEX HEX HEX HEX;

fragmentHEX : [0­9a­fA­F];

Lexer

JSON's lexer + parser

Parser

AST

1 + (2 * 3)

["+", 1, ["*", 2, 3]]

+

1 *

2 3

class Expression(object):def __init__(self, args=None):

self.args = args if args else []

def evaluate(self, env):pass

+

1 *

2 3

AddExpression

MulExpressionIntExpression

IntExpression IntExpression

class IntExpression(Expression):    def __init__(self, value):        self.value = value

    def evaluate(self, env):        return self.value

class AddExpression(BasicMathExpression):    def evaluate(self, env):        return self._evaluate(env, 'Add', lambda x, y: x + y)

class MulExpression(BasicMathExpression):    def evaluate(self, env):        return self._evaluate(env, 'Mul', lambda x, y: x * y)

Tipe data

✔ Integer → ­1 0 1 2✔ Float → ­2.0 1.2 2.3✔ String → "This is a string"✔ List → ["list", 1, 2, 3.0, 

 "This is a string", ["list", 2, 3]]

✔ Empty list → "#nil"✔ Boolean → true false✔ Function✔ Product

Cons

["cons", 1, ["cons", 2, ["cons", 3, "#nil"]]]

["list", 1, 2, 3]

( head tail )

( head ( head tail ) )

( head ( head ( head tail ) ) )

( head ( head ( head nil ) ) )

class Cons(object):    def __init__(self, head=None, tail=None):        self._head = head        self._tail = tail

    @property    def head(self):        return self._head

    @property    def tail(self):        return self._tail

    @staticmethod    def from_seq(seq):        if not seq:            return None

        head = Cons(seq[0])        current = head

        for item in seq[1:]:            next_cons = Cons(item)            current._tail = next_cons            current = next_cons

        return head

    def to_list(self):        result = []

        self.each(result.append)

        return result

    def each(self, f):        f(self.head)

        tail = self.tail        while tail != None:            if isinstance(tail, Cons):                f(tail.head)                tail = tail.tail            else:                f(tail)                tail = None

def map(self, f):pass

def filter(self, f):pass

def reduce(self, f, *args):pass

Scope

Dynamic Scope vs Lexical Scope

Dynamic Scope vs Lexical Scope

two constructs to introduce a variable

["setq", "variable1", 100]

["let", [["variable1", 100]]["print", "@variable1"]]

function's paramenters also introduce local variables

{

"d": "Test factorial.",

"i": true,

"o": ["prog",

["setq", "fac", 

["lambda", ["x"],

["cond",

["<=", "@x", 1], 1,

true, ["*", ["fac", ["­", "@x", 1]], "@x"]]]],

["fac", 3]]}

class BonusEnvironment(dict):    def __init__(self, parent=None):        self._parent = parent

    def __getitem__(self, key):        if key not in self and self._parent:            return self._parent[key]        else:            return super(BonusEnvironment, self).__getitem__(key)

    def set_global(self, key, value):        # by convention, global environment is whose parent         # is None.        if not self._parent:            self[key] = value        else:            self._parent.set_global(key, value)

class GetValExpression(Expression):    def evaluate(self, env):        name = self._evaluated_args(env,                                     'GetVal', ((str, unicode),))        try:            return env[name]        except KeyError:            # search in builtin functions            try:                builtin_class_name = builtin_expressions[name]                builtin_class = globals()[builtin_class_name]                builtin_instance = builtin_class()                return BuiltInFunction(body=builtin_instance)            except KeyError:                return None

Functions

63 builtin functions

["setq", "fib",["lambda", ["n"],

["cond",["<", "@n", 2], 1,true, ["+", ["fib", ["­", "@n", 1]],

["fib", ["­", "@n", 2]]]]]]

class LambdaExpression(Expression):    def __init__(self, params, body):        self.params = params        self.body = body

    def evaluate(self, env):        return Function(self.params, self.body)

class ApplyExpression(Expression):    def __init__(self, funcName, args):        self.funcName = funcName        self.args = args

    def evaluate(self, env):        func = env[self.funcName]        if isinstance(func, Function):            return func.apply(env, self.args)        else:            raise ExpressionException('Apply: Cannot find function with name {0}'.format(self.funcName))

how to add new builtin function?

it should be easy, right?

Demo

Regrets

should not use None as value

class NilType(object):def __nonzero__(self):return False

Nil = NilType()

Thank you!!!