2

Am a ruby guy basically, and got into a situation where I need to make a small dsl in py as follows, I know in ruby following is doable, am looking for exactly same in py

from_a_dsl_file = "
   take_this 'abc'
   and_process_it
   and_give_me_the_output
"

class A
   def take_this abc
   end

   def and_process_it
   end

   def and_give_me_the_output
     'desired'
   end
end

A.new.instance_eval from_a_dsl_file
# => 'desired'

Any hints, or great to have a working example please

thanks in advance

Amol Pujari
  • 2,280
  • 20
  • 42

2 Answers2

3

As I understand it, in Ruby there are some tricky things you can do with function calls that don't require parentheses:

x y

In Ruby, that could be a function call where function x is called with y for the argument.

Well, in Python, we don't have those tricks; if you are calling a function, you need parentheses after the function name. So, I don't think you will have much luck trying to play games with eval() for this.

Better is just to write a parser that parses the language for you and figures out what the language is trying to do. For that, Python has a particularly good library: pyparsing

http://pyparsing.wikispaces.com/

P.S. Just doing a Google search for "Python domain specific language" finds some good links, many in StackOverflow. Here is the best one I found:

Mini-languages in Python

EDIT: Okay, you asked for an example and here you go. This is my first-ever program in PyParsing and it was pretty easy. I didn't even read the documentation; I just worked from the examples in a presentation I found on the web.

Here's the URL of the presentation: http://www.ptmcg.com/geo/python/confs/TxUnconf2008Pyparsing.html

from pyparsing import *

def give_desired_output(s):
    return "desired"

TAKE_THIS = Suppress("take_this") + Suppress(Word(printables))
AND_PROC = Suppress("and_process_it")
AND_GIVE = Keyword("and_give_me_the_output")
AND_GIVE.setParseAction(give_desired_output)

LANGUAGE_LINE = TAKE_THIS | AND_PROC | AND_GIVE

LANGUAGE = ZeroOrMore(LANGUAGE_LINE)


def parse_language(text):
    lst = LANGUAGE.parseString(text)
    assert len(lst) == 1  # trivial language returns a single value
    return lst[0]

if __name__ == "__main__":
    from_a_dsl_file = \
"""
   take_this 'abc'
   and_process_it
   and_give_me_the_output
"""

    print(parse_language(from_a_dsl_file))  # prints the word: desired
Community
  • 1
  • 1
steveha
  • 74,789
  • 21
  • 92
  • 117
1

Sounds like you might want to look at exec() and/or execfile() (and specifically things like the ability to specify the globals and locals available).

(There's also eval(), but it only allows for a single expression, rather than a series of commands.)

Amber
  • 507,862
  • 82
  • 626
  • 550