pogo
Version:
A readable, DSL friendly programming language that compiles to JavaScript
161 lines (130 loc) • 4.52 kB
JavaScript
var _ = require('underscore');
module.exports = function (terminals) {
var cg = this;
return cg.oldTerm(function () {
this.terminals = terminals;
this.subterms('terminals');
this.hasName = function () {
return this.name().length > 0;
};
this.isCall = function () {
if (this.hasName()) {
return this.hasArguments();
} else {
return this.argumentTerminals().length > 1;
}
};
this.name = function () {
return this._name || (this._name = _(this.terminals).filter(function (terminal) {
return terminal.identifier;
}).map(function (identifier) {
return identifier.identifier;
}));
};
this.hasAsyncArgument = function () {
return this._hasAsyncArgument || (this._hasAsyncArgument =
_.any(this.terminals, function (t) { return t.isAsyncArgument; })
);
};
this.hasFutureArgument = function () {
return this._hasFutureArgument || (this._hasFutureArgument =
_.any(this.terminals, function (t) { return t.isFutureArgument; })
);
};
this.hasCallbackArgument = function () {
return this._hasCallbackArgument || (this._hasCallbackArgument =
_.any(this.terminals, function (t) { return t.isCallback; })
);
};
this.hasArguments = function () {
return this._hasArguments || (this._hasArguments =
this.argumentTerminals().length > 0
);
};
this.argumentTerminals = function() {
if (this._argumentTerminals) {
return this._argumentTerminals;
} else {
this._buildBlocks();
return this._argumentTerminals =
_.compact(_.map(this.terminals, function (terminal) {
return terminal.arguments();
}));
}
};
this.arguments = function() {
return this._arguments || (this._arguments = _.flatten(this.argumentTerminals()));
};
this.parameters = function (options) {
var skipFirstParameter = options && options.skipFirstParameter;
if (this._parameters) {
return this._parameters;
}
var args = this.arguments()
if (skipFirstParameter) {
args = args.slice(1);
}
return this._parameters = _(args).map(function (arg) {
return arg.parameter();
});
};
this.hasParameters = function () {
return this._hasParameters || (this._hasParameters =
this.argumentTerminals().length > 0
);
};
this._buildBlocks = function () {
var parameters = [];
var hasParameters = false;
_(this.terminals).each(function (terminal) {
if (terminal.isParameters) {
parameters.push.apply(parameters, terminal.parameters);
hasParameters = true;
} else if (terminal.isBlock) {
terminal.setParameters(parameters);
terminal.notScope = hasParameters;
parameters = [];
hasParameters = false;
}
});
_(parameters).each(function (parm) {
cg.errors.addTermWithMessage(parm, 'block parameter with no block');
});
};
this.hashEntry = function (options) {
var withoutBlock = options && options.withoutBlock;
var args = this.arguments();
var name = this.name();
if (withoutBlock && args.length > 0 && args[args.length - 1].isBlock) {
args = args.slice(0, args.length - 1);
}
if (name.length > 0 && args.length === 1) {
return cg.hashEntry(name, args[0]);
}
if (name.length > 0 && args.length === 0) {
return cg.hashEntry(name);
}
if (name.length === 0 && args.length === 2 && args[0].isString) {
return cg.hashEntry(args[0], args[1])
}
return cg.errors.addTermWithMessage(this, 'cannot be a hash entry');
};
this.hashEntryBlock = function () {
var args = this.arguments();
var lastArgument = args[args.length - 1];
if (lastArgument && lastArgument.isBlock) {
return lastArgument;
}
};
this.hashKey = function () {
var args = this.arguments();
if (args.length === 1 && args[0].isString) {
return args[0];
} else if (!this.hasParameters() && !this.hasArguments() && this.hasName()) {
return this.name();
} else {
return cg.errors.addTermWithMessage(this, 'cannot be a hash key');
}
}
});
};