Advertisement
Guest User

Untitled

a guest
May 10th, 2013
119
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 10.19 KB | None | 0 0
  1. //  See: http://blog.sigfpe.com/2011/01/quine-central.html
  2. //
  3. // "Here's a challenge for you: write a quine that takes as input the name of
  4. //  a language and outputs the same thing implemented in the input language.
  5. //  Much harder than what I just wrote."
  6. //
  7. //  Every program this program outputs operates (almost) identically to itself.
  8. //  When invoked with no arguments, the program outputs an exact copy of itself.
  9. //  When invoked with arguments, it will output a version of itself in another
  10. //  language. This copy, when invoked with no arguments, will also produce an exact
  11. //  copy of itself (but, obviously a different program from its parent-- meaning
  12. //  it does not operate exactly identically to it)
  13. //
  14. //  This program itself is not a quine-- its output for the Scala language is not
  15. //  identical in any way to the input. However, its first generation outputs are
  16. //  quines.
  17. //
  18. //  The approach used in this is relatively simple. Each output program stores a
  19. //  blob of data telling it how to generate a quine for a certain language.
  20. //  
  21. //  The field called "body" stores the main body. It is a printf-style format
  22. //  string with two formats. The first is where the language data will end up, and
  23. //  the second is where a string containing the name of the current language,
  24. //  formatted as a quoted string, will be stored.
  25. //
  26. //  The field named "quot" contains the string delimiters, and the field named
  27. //  "quotr" is a list of string replacements needed for the target language.
  28. //  
  29. //  The field named "lang" contains first a format string that will be used to
  30. //  build the data section for each language. The first few fields, will contain
  31. //  the string-based data, formatted using quot and quotr as in the current language
  32. //  field in body, in "name, left quote, right quote, body, language format string,
  33. //  language delimiter, map outer format string, map inner format string, map
  34. //  delimiter" order. The following field is a map of string replacements for the
  35. //  language, formatted as dictated by the "map" field. The second field in the
  36. //  tuple is a seperator between language definitions.
  37. //
  38. //  The first field in "map" is an "outer format string", which will be formatted
  39. //  with the contents of the map. The second field is a format string, which will
  40. //  be formatted with the source and destination of the required replacements,
  41. //  and concated with the third field as a delimiter. This is then formatted into
  42. //  the outer format string.
  43. //
  44. //  In summary, map is used to build a table of string replacements needed for a
  45. //  target language, which is ten formatted into lang, which is used to build a
  46. //  list of target languages. quot and quotr contain the information required to
  47. //  escape strings into the proper format for a target language. This language
  48. //  table is then formatted into body, and the result is output as the quine in
  49. //  the target language.
  50.  
  51. trait Language {
  52.   val name : String
  53.   def body : String
  54.   val quot : (String, String)
  55.   val lang : (String, String)
  56.   val map  : (String, String, String)
  57.   val quotr: Map[String, String]
  58. }
  59.  
  60. val languages: Seq[Language] = Seq(
  61.   new Object with Language {
  62.     val name = "scala"
  63.     val body = """
  64.      case class Language(name: String, quot: (String, String), body: String, lang: (String, String), map: (String, String, String),
  65.                          quotr: Map[String, String])
  66.      val languages = Seq(%s)
  67.      def quot(target: Language, string: String) =
  68.        target.quot._1+target.quotr.foldLeft(string)((o, t) => o.replace(t._1, t._2))+target.quot._2
  69.      def serializeQuotr(target: Language, source: Language) =
  70.        target.map._1.format(source.quotr.map(t => target.map._2.format(quot(target, t._1), quot(target, t._2))).reduce(_ + target.map._3 + _))
  71.      def generateLanguage(target: Language, source: Language) =
  72.        target.lang._1.format(quot(target, source.name), quot(target, source.quot._1), quot(target, source.quot._2),
  73.                              quot(target, source.body), quot(target, source.lang._1), quot(target, source.lang._2),
  74.                              quot(target, source.map._1), quot(target, source.map._2), quot(target, source.map._3),
  75.                              serializeQuotr(target, source))
  76.      def generate(l: Language) =
  77.        l.body.format(languages.map(l2 => generateLanguage(l, l2)).reduce(_ + l.lang._2 + _), quot(l, l.name))
  78.  
  79.      val myLang = %s
  80.      val language = if(args.length<1) myLang else args.head
  81.      languages.find(_.name == language) match {
  82.        case Some(x) => println(generate(x))
  83.        case None    => println("I dunno that language! Sorry!")
  84.      }
  85.    """
  86.  
  87.     val lang = ("Language(%s, (%s, %s), %s, (%s, %s), (%s, %s, %s), %s)", ", ")
  88.     val quot = ("\"\"\"", "\"\"\"")
  89.     val map  = ("Map(%s)", "%s -> %s", ", ")
  90.     val quotr = Map("dummy"->"dummy")
  91.   }, new Object with Language {
  92.     val name = "python"
  93.     val body = """def main():
  94.      class Language:
  95.        def __init__(self, name, quot, body, lang, map, quotr):
  96.          self.name  = name
  97.          self.quot  = quot
  98.          self.body  = body
  99.          self.lang  = lang
  100.          self.map   = map
  101.          self.quotr = quotr
  102.      languages = %s
  103.      def quot(target, string):
  104.        for i in target.quotr:
  105.          string = string.replace(i[0], i[1])
  106.        return target.quot[0]+string+target.quot[1]
  107.      def serializeQuotr(target, source):
  108.        strs = map(lambda x: target.map[1]%%(quot(target, x[0]), quot(target, x[1])), source.quotr)
  109.        return target.map[0]%%(target.map[2].join(strs))
  110.      def generateLanguage(target, source):
  111.        return target.lang[0]%%(quot(target, source.name), quot(target, source.quot[0]), quot(target, source.quot[1]),
  112.                                quot(target, source.body), quot(target, source.lang[0]), quot(target, source.lang[1]),
  113.                                quot(target, source.map[0]), quot(target, source.map[1]), quot(target, source.map[2]),
  114.                                serializeQuotr(target, source))
  115.      def generate(l):
  116.        strs = map(lambda l2: generateLanguage(l, l2), languages)
  117.        return l.body%%(l.lang[1].join(strs), quot(l, l.name))
  118.      
  119.      import sys
  120.      myLang = %s
  121.      language = myLang if len(sys.argv) < 2 else sys.argv[1]
  122.      for l in languages:
  123.        if l.name == language:
  124.          print generate(l)
  125.          return
  126.      print "Uhm.... "+language+"? I dunno that."
  127.    """+"\nmain()"
  128.     val lang  = ("Language(%s, (%s, %s), %s, (%s, %s), (%s, %s, %s), %s)", ", ")
  129.     val quot  = ("\"\"\"", "\"\"\"")
  130.     val map   = ("[%s]", "(%s, %s)", ", ")
  131.     val quotr = Map("\\" -> "\\\\", "\"" -> "\\\"")
  132.   }, new Object with Language {
  133.     val name = "haskell"
  134.     val body = """
  135.      import Text.Printf
  136.      import System.Environment
  137.      import Data.List hiding (map)
  138.  
  139.      data Language = Language {
  140.        name  :: String,
  141.        quotd :: (String, String),
  142.        body  :: String,
  143.        lang  :: (String, String),
  144.        maps  :: (String, String),
  145.        mapd  :: String, -- hack for fst/snd
  146.        quotr :: [(String, String)]
  147.      }
  148.  
  149.      languages :: [Language]
  150.      languages = [%s]
  151.  
  152.      -- From http://bluebones.net/2007/01/replace-in-haskell/
  153.      -- Why isn't this in the standard library?
  154.      replace :: Eq a => [a] -> [a] -> [a] -> [a]
  155.      replace [] _ _ = []
  156.      replace s find repl =
  157.        if take (length find) s == find
  158.          then repl ++ (replace (drop (length find) s) find repl)
  159.          else [head s] ++ (replace (tail s) find repl)
  160.  
  161.      generate :: Language -> String
  162.      generate t =
  163.        printf (body t) (intercalate (snd $ lang t) $ map generateLanguage languages) (quots $ name t)
  164.        where quots s = (fst $ quotd t) ++ (foldl (\x y -> replace x (fst y) (snd y)) s $ quotr t) ++ (snd $ quotd t)
  165.              serializePair p = printf (snd $ maps t) (quots $ fst p) (quots $ snd p)
  166.              serializeQuot :: Language -> String
  167.              serializeQuot s =
  168.                printf (fst $ maps t) $ intercalate (mapd t) $ map serializePair (quotr s)
  169.              generateLanguage s =
  170.                printf (fst $ lang t) (quots $ name s) (quots $ fst $ quotd s) (quots $ snd $ quotd s)
  171.                                      (quots $ body s) (quots $ fst $ lang s) (quots $ snd $ lang s)
  172.                                      (quots $ fst $ maps s) (quots $ snd $ maps s) (quots $ mapd s)
  173.                                      (serializeQuot s)
  174.  
  175.      main :: IO ()
  176.      main = getArgs >>= (putStrLn . outputString)
  177.        where generate' n Nothing = "Uuu... What kind of a language is "++n++"?"
  178.              generate' _ (Just l) = generate l
  179.              outputString [] = outputString [%s]
  180.              outputString (lang:_) = generate' lang $ find (\l -> (name l)==lang) languages
  181.    """
  182.     val lang  = ("(Language %s (%s, %s) %s (%s, %s) (%s, %s) %s %s)", ", ")
  183.     val quot  = ("\"", "\"")
  184.     val map   = ("[%s]", "(%s, %s)", ", ")
  185.     val quotr = Map("\\" -> "\\\\", "\"" -> "\\\"", "\n" -> "\\n")
  186.   }
  187. )
  188. def quot(target: Language, string: String) =
  189.   target.quot._1+target.quotr.foldLeft(string)((o, t) => o.replace(t._1, t._2))+target.quot._2
  190. def serializeQuotr(target: Language, source: Language) =
  191.   target.map._1.format(source.quotr.map(t => target.map._2.format(quot(target, t._1), quot(target, t._2))).reduce(_ + target.map._3 + _))
  192. def generateLanguage(target: Language, source: Language) =
  193.   target.lang._1.format(quot(target, source.name), quot(target, source.quot._1), quot(target, source.quot._2),
  194.                         quot(target, source.body), quot(target, source.lang._1), quot(target, source.lang._2),
  195.                         quot(target, source.map._1), quot(target, source.map._2), quot(target, source.map._3),
  196.                         serializeQuotr(target, source))
  197. def generate(l: Language) =
  198.   l.body.format(languages.map(l2 => generateLanguage(l, l2)).reduce(_ + l.lang._2 + _), quot(l, l.name))
  199.  
  200. val myLang = "scala"
  201. val language = if(args.length<1) myLang else args.head
  202. languages.find(_.name == language) match {
  203.   case Some(x) => println(generate(x))
  204.   case None    => println("I dunno that language! Sorry!")
  205. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement