Make my pseudocode real

8

I've got some Java pseudocode that uses whitespace instead of curly braces, and I want you to convert it.

I/O

Your program should take an input file along with a number designating how many spaces are used to indent a block. Here's an example:

$ convert.lang input.p 4
// Convert using 4 spaces as the block delimiter
$ convert.lang input.p 2
// Convert using 2 spaces as the block delimiter

It should then convert the result using the specified block delimiter and output the result to stdout.

The meat of the program

Blocks open with : and each line within the block is indented using the block delimiter, like Python code.

while(true):
    System.out.println("Test");

Each : is replaced with a {, and a } is appended to the end of the block.

while(true) {
    System.out.println("Test");
}

Examples

Input:

public class Test:
    public static void main(String[] args):
        System.out.println("Java is verbose...");

Output:

$ convert Test.pseudojava 4
public class Test {
    public static void main(String[] args) {
        System.out.println("Java is verbose...");
    }
}

Input:

main():
  printf("Hello World");

Output:

$ convert test.file 2
main() {
  printf("Hello World");
}

Input:

def generic_op(the_stack, func):
    # Generic op handling code
    b = the_stack.pop()
    if isinstance(b, list):
        if b:
            return
        top = b.pop(0)
        while b:
            top = func(top, b.pop(0))
        the_stack.push(top)
    else:
        a = the_stack.pop()
        return func(a, b)

Output:

$ convert code.py 4
def generic_op(the_stack, func){
    # Generic op handling code
    b = the_stack.pop()
    if isinstance(b, list) {
        if b {
            return
        }
        top = b.pop(0)
        while b {
            top = func(top, b.pop(0))
        }
        the_stack.push(top)
    }
    else {
        a = the_stack.pop()
        return func(a, b)
    }
}

Scoring

The code with the least amount of bytes wins!

phase

Posted 2015-10-19T06:54:56.997

Reputation: 2 540

1Can we assume that the input contains no comments? – Martin Ender – 2015-10-19T07:19:37.170

1@MartinBüttner It may contain comments, but the comments won't contain ':'. Basically, yes. – phase – 2015-10-19T07:32:45.460

3What about labels, which are the usual reason that a line would end in a colon in valid Java source? – Peter Taylor – 2015-10-19T08:11:29.410

1I've never seen a label anywhere but the beginning of a line. – SuperJedi224 – 2015-10-19T13:20:15.257

@PeterTaylor Just ignore those. Let's assume the programmer who made it knew not to use them. – phase – 2015-10-19T14:29:41.110

2I've just been reminded of how much I hate Java. – lirtosiast – 2015-11-16T04:46:57.947

Is the indentation block size a required parameter? – Not that Charles – 2015-11-16T07:49:31.063

@NotthatCharles not if you can detect it automatically, but otherwise yes – phase – 2015-11-16T07:50:34.063

Why would anyone want to convert OUT of <s>Python</s> pseudocode. – Morgan Thrapp – 2015-11-16T17:24:00.183

System.out.println("Java is verbose..."); ಠ_ಠ – user8397947 – 2016-06-26T20:56:05.523

Answers

5

Perl, 41 bytes

#!perl -p0
1while s/( *).*\K:((
\1 .*)+)/ {\2
\1}/

Counting the shebang as two, input is taken from stdin. A command line argument need not be provided. Any valid nesting context can be determined (and matched) without knowing the indentation size.


Regex Break-Down

( *)                   # as many spaces as possible (\1)
    .*                 # as many non-newline characters as possible \
                         (greediness ensures this will always match a full line)
      \K               # keep all that (i.e. look-behind assertion)
        :              # colon at eol (newline must be matched next)
         (
          (
           \n\1        # newline with at least one more space than the first match
                .*     # non-newlines until eol
                  )+   # as many of these lines as possible
                    )  # grouping (\2)

Sample Usage

in1.dat

public class Test:
    public static void main(String[] args):
        System.out.println("Java is verbose...");

Output

$ perl py2java.pl < in1.dat
public class Test {
    public static void main(String[] args) {
        System.out.println("Java is verbose...");
    }
}

in2.dat

main():
  printf("Hello World");

Output

$ perl py2java.pl < in2.dat
main() {
  printf("Hello World");
}

in3.dat

def generic_op(the_stack, func):
    # Generic op handling code
    b = the_stack.pop()
    if isinstance(b, list):
        if b:
            return
        top = b.pop(0)
        while b:
            top = func(top, b.pop(0))
        the_stack.push(top)
    else:
        a = the_stack.pop()
        return func(a, b)

Output

$ perl py2java.pl < in3.dat
def generic_op(the_stack, func) {
    # Generic op handling code
    b = the_stack.pop()
    if isinstance(b, list) {
        if b {
            return
        }
        top = b.pop(0)
        while b {
            top = func(top, b.pop(0))
        }
        the_stack.push(top)
    }
    else {
        a = the_stack.pop()
        return func(a, b)
    }
}

primo

Posted 2015-10-19T06:54:56.997

Reputation: 30 891

i just wrote this in ruby – Not that Charles – 2015-11-16T07:54:49.807

2

Python 3, 299 265 bytes

import sys;s=int(sys.argv[2]);t="";b=0
for l in open(sys.argv[1]):
 h=l;g=0
 for c in l:
  if c!=" ":break
  g+=1
 if g/s<b:h=" "*g+"}\n"+h;b-=1
 if l.strip().endswith(":"):h=l.split(":")[0];h+=" {";b+=1
 t+=h+"\n"
b-=1
while b>-1:
 t+=" "*(b*s)+"}\n"b-=1
print(t)

Boom bam pow.

Algorithm used:

//global vars
string total //total modified program
int b //indent buffer

line thru lines: //iterate over every line
  string mline = "" //line to be added to the total

  //calculate the amount of spaces before the line (could be a lot easier)
  int spaces = 0 //total spaces
  c thru line: //go through every character in the line
    if c != " ": //if the current char isn't a space (meaning we went though all of them
        break //break out of iterating through chars
    spaces++ //increment the spaces because we've hit a space (hurr derr)

  if spaces/SPACE_SETTING < b: //if indent count of the current line is less than the indent buffer
    mline = "}\n" + line //add closing bracket to beginning of line
    b-- //decrement buffer

  if line.endswith(":"): //if the line ends with a `:`
    remove : from line
    mline += " {" //append {
    b++ //increment buffer
  total += mline //add modified line to total

print(total)

phase

Posted 2015-10-19T06:54:56.997

Reputation: 2 540

Can you include an explanation? – TanMath – 2015-11-16T05:22:22.703

@TanMath Added the algorithm I used – phase – 2015-11-16T05:39:04.343

Does it work with Python 2? – wb9688 – 2015-11-17T07:16:54.140

@wb9688 No idea, I only tested it with Python 3 – phase – 2015-11-17T07:17:34.943

I just tested, and it works with Python 2 – wb9688 – 2015-11-17T07:25:24.830

2

Ruby, 70

x=$_+"
"
1while x.sub! /^(( *).*):
((\2 .*?
)*)/,'\1 {
\3\2}
'
$><<x

Adds a trailing newline. Does not need the indent block-size parameter.

Run this with -n0 (this is really 68+2). Thank you greatly to @primo for saving over a dozen bytes.

Not that Charles

Posted 2015-10-19T06:54:56.997

Reputation: 1 905

I think -p0 also works for ruby (-0 reads all input at once, -p stores stdin into $_, and auto-prints it at the end). – primo – 2015-11-16T08:47:44.063

@primo Good point. In case it wasn't clear with my comment above, this isn't a port of your code, but my own work that does exactly what yours does (but with more bytes) – Not that Charles – 2015-11-16T15:01:15.520

I understood correctly, just providing a tip to remove the (rather verbose) x=$<.readlines*''. While I'm doing that, sub! also has a two parameter overload (rather than one paramater + block) that accepts a replacement string, so you can use \1, \2, etc. instead of needing to concatenate it all. – primo – 2015-11-16T15:08:25.053

@primo Thanks! I tried the two-parameter version before and abandoned it at some point last night. – Not that Charles – 2015-11-16T16:53:20.797