Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // See: http://blog.sigfpe.com/2011/01/quine-central.html
- //
- // "Here's a challenge for you: write a quine that takes as input the name of
- // a language and outputs the same thing implemented in the input language.
- // Much harder than what I just wrote."
- //
- // Every program this program outputs operates (almost) identically to itself.
- // When invoked with no arguments, the program outputs an exact copy of itself.
- // When invoked with arguments, it will output a version of itself in another
- // language. This copy, when invoked with no arguments, will also produce an exact
- // copy of itself (but, obviously a different program from its parent-- meaning
- // it does not operate exactly identically to it)
- //
- // This program itself is not a quine-- its output for the Scala language is not
- // identical in any way to the input. However, its first generation outputs are
- // quines.
- //
- // The approach used in this is relatively simple. Each output program stores a
- // blob of data telling it how to generate a quine for a certain language.
- //
- // The field called "body" stores the main body. It is a printf-style format
- // string with two formats. The first is where the language data will end up, and
- // the second is where a string containing the name of the current language,
- // formatted as a quoted string, will be stored.
- //
- // The field named "quot" contains the string delimiters, and the field named
- // "quotr" is a list of string replacements needed for the target language.
- //
- // The field named "lang" contains first a format string that will be used to
- // build the data section for each language. The first few fields, will contain
- // the string-based data, formatted using quot and quotr as in the current language
- // field in body, in "name, left quote, right quote, body, language format string,
- // language delimiter, map outer format string, map inner format string, map
- // delimiter" order. The following field is a map of string replacements for the
- // language, formatted as dictated by the "map" field. The second field in the
- // tuple is a seperator between language definitions.
- //
- // The first field in "map" is an "outer format string", which will be formatted
- // with the contents of the map. The second field is a format string, which will
- // be formatted with the source and destination of the required replacements,
- // and concated with the third field as a delimiter. This is then formatted into
- // the outer format string.
- //
- // In summary, map is used to build a table of string replacements needed for a
- // target language, which is ten formatted into lang, which is used to build a
- // list of target languages. quot and quotr contain the information required to
- // escape strings into the proper format for a target language. This language
- // table is then formatted into body, and the result is output as the quine in
- // the target language.
- trait Language {
- val name : String
- def body : String
- val quot : (String, String)
- val lang : (String, String)
- val map : (String, String, String)
- val quotr: Map[String, String]
- }
- val languages: Seq[Language] = Seq(
- new Object with Language {
- val name = "scala"
- val body = """
- case class Language(name: String, quot: (String, String), body: String, lang: (String, String), map: (String, String, String),
- quotr: Map[String, String])
- val languages = Seq(%s)
- def quot(target: Language, string: String) =
- target.quot._1+target.quotr.foldLeft(string)((o, t) => o.replace(t._1, t._2))+target.quot._2
- def serializeQuotr(target: Language, source: Language) =
- target.map._1.format(source.quotr.map(t => target.map._2.format(quot(target, t._1), quot(target, t._2))).reduce(_ + target.map._3 + _))
- def generateLanguage(target: Language, source: Language) =
- target.lang._1.format(quot(target, source.name), quot(target, source.quot._1), quot(target, source.quot._2),
- quot(target, source.body), quot(target, source.lang._1), quot(target, source.lang._2),
- quot(target, source.map._1), quot(target, source.map._2), quot(target, source.map._3),
- serializeQuotr(target, source))
- def generate(l: Language) =
- l.body.format(languages.map(l2 => generateLanguage(l, l2)).reduce(_ + l.lang._2 + _), quot(l, l.name))
- val myLang = %s
- val language = if(args.length<1) myLang else args.head
- languages.find(_.name == language) match {
- case Some(x) => println(generate(x))
- case None => println("I dunno that language! Sorry!")
- }
- """
- val lang = ("Language(%s, (%s, %s), %s, (%s, %s), (%s, %s, %s), %s)", ", ")
- val quot = ("\"\"\"", "\"\"\"")
- val map = ("Map(%s)", "%s -> %s", ", ")
- val quotr = Map("dummy"->"dummy")
- }, new Object with Language {
- val name = "python"
- val body = """def main():
- class Language:
- def __init__(self, name, quot, body, lang, map, quotr):
- self.name = name
- self.quot = quot
- self.body = body
- self.lang = lang
- self.map = map
- self.quotr = quotr
- languages = %s
- def quot(target, string):
- for i in target.quotr:
- string = string.replace(i[0], i[1])
- return target.quot[0]+string+target.quot[1]
- def serializeQuotr(target, source):
- strs = map(lambda x: target.map[1]%%(quot(target, x[0]), quot(target, x[1])), source.quotr)
- return target.map[0]%%(target.map[2].join(strs))
- def generateLanguage(target, source):
- return target.lang[0]%%(quot(target, source.name), quot(target, source.quot[0]), quot(target, source.quot[1]),
- quot(target, source.body), quot(target, source.lang[0]), quot(target, source.lang[1]),
- quot(target, source.map[0]), quot(target, source.map[1]), quot(target, source.map[2]),
- serializeQuotr(target, source))
- def generate(l):
- strs = map(lambda l2: generateLanguage(l, l2), languages)
- return l.body%%(l.lang[1].join(strs), quot(l, l.name))
- import sys
- myLang = %s
- language = myLang if len(sys.argv) < 2 else sys.argv[1]
- for l in languages:
- if l.name == language:
- print generate(l)
- return
- print "Uhm.... "+language+"? I dunno that."
- """+"\nmain()"
- val lang = ("Language(%s, (%s, %s), %s, (%s, %s), (%s, %s, %s), %s)", ", ")
- val quot = ("\"\"\"", "\"\"\"")
- val map = ("[%s]", "(%s, %s)", ", ")
- val quotr = Map("\\" -> "\\\\", "\"" -> "\\\"")
- }, new Object with Language {
- val name = "haskell"
- val body = """
- import Text.Printf
- import System.Environment
- import Data.List hiding (map)
- data Language = Language {
- name :: String,
- quotd :: (String, String),
- body :: String,
- lang :: (String, String),
- maps :: (String, String),
- mapd :: String, -- hack for fst/snd
- quotr :: [(String, String)]
- }
- languages :: [Language]
- languages = [%s]
- -- From http://bluebones.net/2007/01/replace-in-haskell/
- -- Why isn't this in the standard library?
- replace :: Eq a => [a] -> [a] -> [a] -> [a]
- replace [] _ _ = []
- replace s find repl =
- if take (length find) s == find
- then repl ++ (replace (drop (length find) s) find repl)
- else [head s] ++ (replace (tail s) find repl)
- generate :: Language -> String
- generate t =
- printf (body t) (intercalate (snd $ lang t) $ map generateLanguage languages) (quots $ name t)
- where quots s = (fst $ quotd t) ++ (foldl (\x y -> replace x (fst y) (snd y)) s $ quotr t) ++ (snd $ quotd t)
- serializePair p = printf (snd $ maps t) (quots $ fst p) (quots $ snd p)
- serializeQuot :: Language -> String
- serializeQuot s =
- printf (fst $ maps t) $ intercalate (mapd t) $ map serializePair (quotr s)
- generateLanguage s =
- printf (fst $ lang t) (quots $ name s) (quots $ fst $ quotd s) (quots $ snd $ quotd s)
- (quots $ body s) (quots $ fst $ lang s) (quots $ snd $ lang s)
- (quots $ fst $ maps s) (quots $ snd $ maps s) (quots $ mapd s)
- (serializeQuot s)
- main :: IO ()
- main = getArgs >>= (putStrLn . outputString)
- where generate' n Nothing = "Uuu... What kind of a language is "++n++"?"
- generate' _ (Just l) = generate l
- outputString [] = outputString [%s]
- outputString (lang:_) = generate' lang $ find (\l -> (name l)==lang) languages
- """
- val lang = ("(Language %s (%s, %s) %s (%s, %s) (%s, %s) %s %s)", ", ")
- val quot = ("\"", "\"")
- val map = ("[%s]", "(%s, %s)", ", ")
- val quotr = Map("\\" -> "\\\\", "\"" -> "\\\"", "\n" -> "\\n")
- }
- )
- def quot(target: Language, string: String) =
- target.quot._1+target.quotr.foldLeft(string)((o, t) => o.replace(t._1, t._2))+target.quot._2
- def serializeQuotr(target: Language, source: Language) =
- target.map._1.format(source.quotr.map(t => target.map._2.format(quot(target, t._1), quot(target, t._2))).reduce(_ + target.map._3 + _))
- def generateLanguage(target: Language, source: Language) =
- target.lang._1.format(quot(target, source.name), quot(target, source.quot._1), quot(target, source.quot._2),
- quot(target, source.body), quot(target, source.lang._1), quot(target, source.lang._2),
- quot(target, source.map._1), quot(target, source.map._2), quot(target, source.map._3),
- serializeQuotr(target, source))
- def generate(l: Language) =
- l.body.format(languages.map(l2 => generateLanguage(l, l2)).reduce(_ + l.lang._2 + _), quot(l, l.name))
- val myLang = "scala"
- val language = if(args.length<1) myLang else args.head
- languages.find(_.name == language) match {
- case Some(x) => println(generate(x))
- case None => println("I dunno that language! Sorry!")
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement