Use Error objects.

This commit is contained in:
Young Hahn 2011-07-25 02:26:20 -04:00
parent 9165b20d53
commit e14d8f3720
9 changed files with 87 additions and 68 deletions

View File

@ -143,10 +143,7 @@ function number(n) {
} else if (typeof(n) === 'number') {
return n;
} else {
throw {
error: "RuntimeError",
message: "color functions take numbers as parameters"
};
throw new Error('Color functions take numbers as parameters.');
}
}

View File

@ -4,6 +4,8 @@ var carto = {
Parser: require('./parser').Parser,
Renderer: require('./renderer').Renderer,
tree: require('./tree'),
// @TODO
writeError: function(ctx, options) {
var message = '';
var extract = ctx.extract;

View File

@ -171,26 +171,24 @@ carto.Parser = function Parser(env) {
}
}
function errorMessage(message, i) {
if (typeof i === 'undefined') i = furthest;
lines = input.split('\n');
line = (input.slice(0, i).match(/\n/g) || '').length + 1;
for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++; }
var error = new Error((message || 'Syntax Error') + ' on line ' + line);
return _(error).extend({
name: 'ParseError',
// Make an error object from a passed set of properties.
// Accepted properties:
// - `message`: Text of the error message.
// - `filename`: Filename where the error occurred.
// - `index`: Char. index where the error occurred.
function makeError(err) {
_(err).defaults({
index: furthest,
filename: env.filename,
line: line,
index: i,
column: column,
extract: [
lines[line - 2],
lines[line - 1],
lines[line]
]
message: 'Parse error.',
line: 0,
column: -1
});
err.line = (input.slice(0, err.index).match(/\n/g) || '').length + 1;
for (var n = err.index; n >= 0 && input.charAt(n) !== '\n'; n--) {
err.column++;
};
return new Error(_('<%=filename%>:<%=line%>:<%=column%> <%=message%>').template(err));
}
this.env = env = env || {};
@ -266,10 +264,9 @@ carto.Parser = function Parser(env) {
}
if (level > 0) {
// TODO: make invalid instead
throw _(new Error('Missing closing `}`')).extend({
index: i,
line: 0,
filename: env.filename
throw makeError({
message:'Missing closing `}`',
index:i
});
}
@ -283,42 +280,18 @@ carto.Parser = function Parser(env) {
root = new tree.Ruleset([], $(this.parsers.primary));
root.root = true;
root.getLine = function(index) {
return index ? (input.slice(0, index).match(/\n/g) || '').length : null;
};
root.makeError = function(e) {
lines = input.split('\n');
line = root.getLine(e.index);
for (var n = e.index, column = -1;
n >= 0 && input.charAt(n) !== '\n';
n--) { column++ }
return _(new Error(e.message)).extend({
type: e.type,
filename: e.filename,
index: e.index,
line: typeof(line) === 'number' ? line + 1 : null,
column: column,
extract: [
lines[line - 1],
lines[line],
lines[line + 1]
]
});
}
// Get an array of Ruleset objects, flattened
// and sorted according to specificitySort
root.toList = (function() {
var line, lines, column, _ = require('underscore')._;
return function(env) {
env.error = function(e) {
if (!env.errors) env.errors = [];
env.errors.push(root.makeError(e));
if (!env.errors) env.errors = new Error('');
if (env.errors.message) {
env.errors.message += '\n' + makeError(e).message;
} else {
env.errors.message = makeError(e).message;
}
};
env.errors = [];
env.frames = env.frames || [];
// call populates Invalid-caused errors
@ -353,7 +326,10 @@ carto.Parser = function Parser(env) {
// showing the line where the parse error occured.
// We split it up into two parts (the part which parsed,
// and the part which didn't), so we can color them differently.
if (i < input.length - 1) throw errorMessage('Parse error', i);
if (i < input.length - 1) throw makeError({
message:'Parse error.',
index:i
});
return root;
},
@ -639,7 +615,7 @@ carto.Parser = function Parser(env) {
$('(') && (args = $(this.entities.arguments)) && $(')');
if (elements.length > 0 && ($(';') || peek('}'))) {
throw 'Calls are not yet supported';
throw new Error('Calls are not yet supported.');
return new tree.mixin.Call(elements, args, index);
}
},
@ -680,7 +656,7 @@ carto.Parser = function Parser(env) {
if (value = $(this.expression)) {
params.push({ name: param.name, value: value });
} else {
throw new Error('Expected value');
throw new Error('Expected value.');
}
} else {
params.push({ name: param.name });
@ -695,7 +671,7 @@ carto.Parser = function Parser(env) {
ruleset = $(this.block);
if (ruleset) {
throw 'Definitions should not exist here';
throw new Error('Definitions should not exist here.');
return new tree.mixin.Definition(name, params, ruleset);
}
}
@ -781,7 +757,10 @@ carto.Parser = function Parser(env) {
filters.add(f);
conditions++;
} else if (attachment) {
throw errorMessage('Encountered second attachment name', i - 1);
throw makeError({
message:'Encountered second attachment name.',
index:i - 1
});
} else {
attachment = a;
}

View File

@ -17,8 +17,7 @@ carto.Renderer.prototype.render = function render(m, callback) {
env = _(this.env).defaults({
benchmark: false,
validation_data: false,
effects: [],
errors: []
effects: []
});
var output = [];
@ -73,7 +72,7 @@ carto.Renderer.prototype.render = function render(m, callback) {
}
// Exit on errors.
if (env.errors.length) return callback(env.errors);
if (env.errors) return callback(env.errors);
if (!map_properties.srs)
map_properties.srs = 'srs="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over"';

View File

@ -170,7 +170,7 @@ tree.Ruleset.prototype = {
} else if (rule instanceof tree.Rule) {
rules.push(rule);
} else if (rule instanceof tree.Invalid) {
env.errors.push(rule);
env.error(rule);
}
}

View File

@ -0,0 +1,40 @@
var path = require('path'),
sys = require('sys'),
assert = require('assert'),
fs = require('fs');
var carto = require('../lib/carto');
var tree = require('../lib/carto/tree');
var helper = require('./support/helper');
helper.files('errorhandling', 'mml', function(file) {
exports['errorhandling ' + path.basename(file)] = function(beforeExit) {
var completed = false;
var renderResult;
var mml = helper.mml(file);
new carto.Renderer({
paths: [ path.dirname(file) ],
data_dir: path.join(__dirname, '../data'),
local_data_dir: path.join(__dirname, 'rendering'),
filename: file
}).render(mml, function (err) {
var result = helper.resultFile(file);
var output = err.message;
// @TODO for some reason, fs.readFile includes an additional \n
// at the end of read files. Determine why.
fs.readFile(helper.resultFile(file), 'utf8', function(err, data) {
assert.deepEqual(output, data.substr(0, data.length - 1));
});
});
beforeExit(function() {
/*
if (!completed && renderResult) {
console.warn(helper.stylize('renderer produced:', 'bold'));
console.warn(renderResult);
}
assert.ok(completed, 'Rendering finished.');
*/
});
}
});

View File

@ -1 +1 @@
[{"message":"Unrecognized selector: polygonopacity","index":41,"type":"syntax","filename":"[absolute path]","line":3,"column":2,"extract":[" polygon-fill: #f00;"," polygonopacity: 0.5;","}"]}]
invalid_property.mss:3:2 Unrecognized rule: polygonopacity

View File

@ -1 +1 @@
[{"message":"Invalid value for polygon-opacity, a valid float is expected. #ff0000 was given.","index":19,"type":"syntax","filename":"[absolute path]","line":2,"column":2,"extract":["#world[zoom=5] {"," polygon-opacity: #f00;","}"]}]
invalid_value.mss:2:2 Invalid value for polygon-opacity, a valid float is expected. #ff0000 was given.

View File

@ -1 +1,3 @@
[{"message":"variable @something is undefined","index":33,"type":"runtime","filename":"[absolute path]","line":2,"column":16,"extract":["#world[zoom=5] {"," polygon-fill: @something;","}"]}]
undefined_variable.mss:2:16 variable @something is undefined
undefined_variable.mss:3:14 variable @something is undefined
undefined_variable.mss:4:22 variable @something is undefined