Skip to content

Instantly share code, notes, and snippets.

@levjj
Last active August 29, 2015 13:56
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save levjj/8817834 to your computer and use it in GitHub Desktop.
Save levjj/8817834 to your computer and use it in GitHub Desktop.
Units of measure with sweet.js
// Some minimal class for values with units
// (nothing exciting going on...)
function Unit(name,val) {
this.name = name;
this.val = val;
}
Unit.prototype.toString = function() {
return this.val + " " + this.name;
}
Unit.prototype.add = function(other) {
if ("number" == typeof other) return new Unit(this.name, this.val + other);
if (other.name != this.name) throw new Error("does not work");
return new Unit(this.name, this.val + other.val);
}
Unit.prototype.times = function(other) {
if ("number" == typeof other) return new Unit(this.name, this.val * other);
if (other.name != this.name) throw new Error("does not work");
return new Unit(this.name, this.val * other.val);
}
Unit.prototype.lessThan = function(other) {
if ("number" == typeof other) return this.val < other;
if (other.name != this.name) throw new Error("does not work");
return this.val < other.val;
}
// How to define new units
// You can have basic SI units or derived units.
macro unit {
rule { $name = $r:expr } => {
macro $name {
rule infix {$x:expr |} => { ($r).times($x) }
}
}
rule { $name } => {
macro $name {
case infix {$x:expr | $name} => {
var name = #{$name};
var nom = name[0].token.value;
return withSyntax($nlit = [makeValue(nom,name)]) {
return #{new Unit($nlit, $x)}
}
}
}
}
}
// Adding some syntactic sugar
// (Using "++" so we don't lose native "+")
macro ++ { rule infix { $x:expr | $y:expr } => { $x.add($y) } }
macro << { rule infix { $x:expr | $y:expr } => { $x.lessThan($y) } }
// Now, let's define some units!
unit m;
unit km = 1000 m;
unit mile = 1609 m;
unit miles = 1 mile;
unit s;
unit min = 60 s;
unit h = 60 min;
unit day = 24 h;
// And here you can use them:
alert(2 miles);
alert(1.5 km ++ 100 m);
alert(2 miles << 10 km);
alert(1 day << 23 h ++ 70 min);
var todos = [30 min, 2 h, 45 min, 2.5 h, 30 min];
var done = 0 min;
while (done << 5 h) {
done = done ++ todos.shift();
}
alert("Not enough time to finish: " + todos);
// Hint: Paste this file into http://sweetjs.org/browser/editor.html to try it out!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment