| Index: experimental/webtry/webtry.go
 | 
| diff --git a/experimental/webtry/webtry.go b/experimental/webtry/webtry.go
 | 
| index ea59bc1c422b7d7d57821d4d663229644f356831..34aa47e2827a3e80342f5a6c715df7162944c786 100644
 | 
| --- a/experimental/webtry/webtry.go
 | 
| +++ b/experimental/webtry/webtry.go
 | 
| @@ -22,6 +22,7 @@ import (
 | 
|  	"os/exec"
 | 
|  	"path/filepath"
 | 
|  	"regexp"
 | 
| +	"strconv"
 | 
|  	"strings"
 | 
|  	"text/template"
 | 
|  	"time"
 | 
| @@ -86,6 +87,9 @@ var (
 | 
|  	// workspaceLink is the regex that matches URLs paths for workspaces.
 | 
|  	workspaceLink = regexp.MustCompile("^/w/([a-z0-9-]+)$")
 | 
|  
 | 
| +	// errorRE is ther regex that matches compiler errors and extracts the line / column information.
 | 
| +	errorRE = regexp.MustCompile("^.*.cpp:(\\d+):(\\d+):\\s*(.*)")
 | 
| +
 | 
|  	// workspaceNameAdj is a list of adjectives for building workspace names.
 | 
|  	workspaceNameAdj = []string{
 | 
|  		"autumn", "hidden", "bitter", "misty", "silent", "empty", "dry", "dark",
 | 
| @@ -405,10 +409,10 @@ func expandGyp(hash string) error {
 | 
|  
 | 
|  // response is serialized to JSON as a response to POSTs.
 | 
|  type response struct {
 | 
| -	Message string `json:"message"`
 | 
| -	StdOut  string `json:"stdout"`
 | 
| -	Img     string `json:"img"`
 | 
| -	Hash    string `json:"hash"`
 | 
| +	Message       string         `json:"message"`
 | 
| +	CompileErrors []compileError `json:"compileErrors"`
 | 
| +	Img           string         `json:"img"`
 | 
| +	Hash          string         `json:"hash"`
 | 
|  }
 | 
|  
 | 
|  // doCmd executes the given command line string; the command being
 | 
| @@ -447,6 +451,23 @@ func reportTryError(w http.ResponseWriter, r *http.Request, err error, message,
 | 
|  	}
 | 
|  	glog.Errorf("%s\n%s", message, err)
 | 
|  	resp, err := json.Marshal(m)
 | 
| +
 | 
| +	if err != nil {
 | 
| +		http.Error(w, "Failed to serialize a response", 500)
 | 
| +		return
 | 
| +	}
 | 
| +	w.Header().Set("Content-Type", "text/plain")
 | 
| +	w.Write(resp)
 | 
| +}
 | 
| +
 | 
| +func reportCompileError(w http.ResponseWriter, r *http.Request, compileErrors []compileError, hash string) {
 | 
| +	m := response{
 | 
| +		CompileErrors: compileErrors,
 | 
| +		Hash:          hash,
 | 
| +	}
 | 
| +
 | 
| +	resp, err := json.Marshal(m)
 | 
| +
 | 
|  	if err != nil {
 | 
|  		http.Error(w, "Failed to serialize a response", 500)
 | 
|  		return
 | 
| @@ -794,6 +815,12 @@ func cleanCompileOutput(s, hash string) string {
 | 
|  	return strings.Replace(s, old, "usercode.cpp:", -1)
 | 
|  }
 | 
|  
 | 
| +type compileError struct {
 | 
| +	Line   int    `json:"line"`
 | 
| +	Column int    `json:"column"`
 | 
| +	Error  string `json:"error"`
 | 
| +}
 | 
| +
 | 
|  // mainHandler handles the GET and POST of the main page.
 | 
|  func mainHandler(w http.ResponseWriter, r *http.Request) {
 | 
|  	glog.Infof("Main Handler: %q\n", r.URL.Path)
 | 
| @@ -869,10 +896,40 @@ func mainHandler(w http.ResponseWriter, r *http.Request) {
 | 
|  		}
 | 
|  
 | 
|  		message, err := doCmd(cmd)
 | 
| +
 | 
| +		outputLines := strings.Split(message, "\n")
 | 
| +		errorLines := []compileError{}
 | 
| +		for _, line := range outputLines {
 | 
| +			match := errorRE.FindStringSubmatch(line)
 | 
| +			if len(match) > 0 {
 | 
| +				lineNumber, parseError := strconv.Atoi(match[1])
 | 
| +				if parseError != nil {
 | 
| +					glog.Errorf("ERROR: Couldn't parse line number from %s\n", match[1])
 | 
| +					continue
 | 
| +				}
 | 
| +				columnNumber, parseError := strconv.Atoi(match[2])
 | 
| +				if parseError != nil {
 | 
| +					glog.Errorf("ERROR: Couldn't parse column number from %s\n", match[2])
 | 
| +					continue
 | 
| +				}
 | 
| +				errorLines = append(errorLines,
 | 
| +					compileError{
 | 
| +						Line:   lineNumber,
 | 
| +						Column: columnNumber,
 | 
| +						Error:  match[3],
 | 
| +					})
 | 
| +			}
 | 
| +		}
 | 
| +
 | 
|  		if err != nil {
 | 
| -			reportTryError(w, r, err, "Failed to run the code:\n"+message, hash)
 | 
| +			if len(errorLines) > 0 {
 | 
| +				reportCompileError(w, r, errorLines, hash)
 | 
| +			} else {
 | 
| +				reportTryError(w, r, err, "Failed to run the code:\n"+message, hash)
 | 
| +			}
 | 
|  			return
 | 
|  		}
 | 
| +
 | 
|  		png, err := ioutil.ReadFile("../../../inout/" + hash + ".png")
 | 
|  		if err != nil {
 | 
|  			reportTryError(w, r, err, "Failed to open the generated PNG.", hash)
 | 
| 
 |